From f0838dd5fc15d4540b6727fc14ef9ef549ea2cdf Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 30 Nov 2023 22:16:10 +0300 Subject: [PATCH 001/110] Added new image DolphinSaved_113x58.png for all "saved" pages --- assets/icons/iButton/DolphinSaved_113x58.png | Bin 0 -> 1788 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/icons/iButton/DolphinSaved_113x58.png diff --git a/assets/icons/iButton/DolphinSaved_113x58.png b/assets/icons/iButton/DolphinSaved_113x58.png new file mode 100644 index 0000000000000000000000000000000000000000..0d3f5eedc6e25d6c74306dff50b60642fab08b5b GIT binary patch literal 1788 zcmbVNc~BEq7*DB_BA6L;s;I@X22l~S*_`V}0zwiLB^&_-kD{B+3yHAVuvthz#ZmFD zT9xs@kwc}3BBM?b0Z|D#cHj5j`+mRgp4}J~ zF_Y&u){VpA@WN)Pb?lnLz6w_t_UpQ4{A6|+!)W4}7|O`laT;)f4U`^0VI-aibO1M` zr__M}4(Ic9b8I{luMJla6ba)_9oRuySu}?e5ah7pL=s>iJxDZLl>C=f=lGD>pybEN zw20QK0w(jU3>w5_M8pyqNd#u#2L(a_4h2g<0tSa1WU|Gka47lxyb4x!9t-(UzY3G2 zlT*ED{h1B7#s>lFG%?FbqY}sgM{EON5AAD3%Gt5`_#^h@{ZK!)Gnh z2BSi!4jr(^?v#8J!&ntUq1|qW?Gl)x6NMrS!-R-fC>9G?4S_A)!r%^p#pW}}pawRA zHd`4pWr3WGxSmR7lzi6P_hFD$t@Z=4#Ws*EHf=%&ZWW4PL`ag(*!s0?j1K(k#z(bn zvFTPI)BzinN)v2Nj6Q>4Hh-Tsn~0L>dhyN5vs3b!ezm zDh>{jV}sZ*i;cl81Q@h!W^E5(C7;A9R5ZXDijJkIBC{QA}zSOaq9V4c{miU77mEd;2 zuii8-3O>_Ihj$N8fB5&+yIHbx+$g^vS?PZ6qPukQ-mtdqqI`aq7QE8jXb>~%_^#~G zVPrKP>`hxc_UQKLxvkedhU%jqIffKmBhM=rv=lbxU zZFx^?CjH~*R(+0qu6*tw(TMrPi~5E?tW`%qR_?|qLQt4o5xiiAa9=#=wyNmtFEb{= zkw;oD(-uo*GZ!8E77r>Kac4r(va2UYc3i-wx;L%R-H@)``q%tfLr2Kr@A z!zV>`=JA&BzMOMn^@JC7UiF9Jqf4uMxu&cyE|zS|O1xc`t_k1OHCM)U zQJieQn;ciIr{{LQEQR;_ZI0U!Gp=n{PF+?}-A!)wrQCUM;sk>E5#aYK_c#8vQzH(! zNpyYnE!S#uR;ijFZ+Z}3dZbI{rL1U;z}?PVsMz|}e>%_MAo1+&-S*Ai6?1)4a$iWw zc}H?RA1u9j+SrK4AR8{_f$>zT;&8_6Of>X>5JA ze9F Date: Thu, 30 Nov 2023 22:17:06 +0300 Subject: [PATCH 002/110] New image DolphinDone_80x58.png added --- assets/icons/iButton/DolphinDone_80x58.png | Bin 0 -> 1664 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/icons/iButton/DolphinDone_80x58.png diff --git a/assets/icons/iButton/DolphinDone_80x58.png b/assets/icons/iButton/DolphinDone_80x58.png new file mode 100644 index 0000000000000000000000000000000000000000..594d62d5294997399bc3b256fbe7685ce10b146d GIT binary patch literal 1664 zcmbVNc~BE)6wheY2!uKFLY*phgJAoI;~(9b-S2(h_kQpF-Zi@^ zF+PgtHqDL0;qcVaN)5Xvvag&wj{R2ntG{IzUnWw^ETRmI4WkK8n4Z!RfZBv*5gG#1 zJ63#0gm5_H9b}T0(Z(&5iMAyfDpT!HDDqb46vJwW~kNcFY38LI^aOT(OO4TNw@UFO4^9 zTaz3X0@M&zDwoFDnivAcz-<2B?#QLcvXLjyBwHBFsHE^*6Jci5N(G<25$Z|3oFF79 zt{0&K1d|yAVyOrc=nxShkm0BVg>_OwC(@1Cc@tix3X)1BkVqB;1;KD+Br265;Soxe zN-Rdg!lmdKR&BO2m>DO=e3Pv2Q7rOStUQ7yFovR&D9Sk235nShLs_#a3xG(35HLFq z!%4I2WR9y!uYy(*G?_=}RWxM+M$#-N-#`HpAu80Tmd;G97`! zdI?Mr{87CA|E3RQNrA3j`A_eR9kC7R5?@aPyLmlNgqa;8nw^%VblFu7XWV|ZGAzm7 z-ns8C-3V|CWLx`RUVV5?e=~JLXGNd*gA2VSy}M^liFW=t^rC%5`mI^MKJ^z*yC+9$ zK8y8opgw0i#OZbK-@bIOr+sL3X*0ny?F_5$?^u;L5LsJ%K{s=fe|&Jv>M52PH5+{E zciwC+?Q1wXec-Dn?aE=B+ip?UBV`Bm*T(s!wWZ~plEuod;*9$(j?$d6^(EcKbW!X< z&nIP6%$5Z)#Sc{zYqC;eHfJr#r`xJt{34$f<9D)}sVN9J6SzfMQhTpr?kB2_2ge#4 zPMiznH%5_{H{8XZyCE8Z^qt3(nNamZCKd_dTt1 zybD4vFW|RcM-rOAUY>VP`H4R@hUX>mS_}#FURP5QO}9;kzD&7Mf0X!18#*Cy#s=lb zoGCF8teZgFA$ z+RoI3!Q}^!2oJhss<8vOJLqi_j*V;@D?$qOzS!qAdI~fh>f!$Rlk&;`Vf`4<% z;twaDuf~1bzjhOXb@_XjZ49oi7zcZBs XY(V!OcIS4x{t4>Hc;)f%%(edjvT}hx literal 0 HcmV?d00001 From f7de65684a7caf7671bb534bc880d33eccf0758d Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 30 Nov 2023 22:19:24 +0300 Subject: [PATCH 003/110] Replaced dolphins on all scenes accroding to new UI specs --- .../main/ibutton/scenes/ibutton_scene_save_success.c | 4 +--- .../main/infrared/scenes/infrared_scene_edit_rename_done.c | 3 +-- .../main/infrared/scenes/infrared_scene_learn_done.c | 5 ++--- applications/main/lfrfid/scenes/lfrfid_scene_save_success.c | 3 +-- applications/main/nfc/scenes/nfc_scene_save_success.c | 3 +-- applications/main/subghz/scenes/subghz_scene_save_success.c | 3 +-- .../scenes/bt_settings_scene_forget_dev_success.c | 2 +- 7 files changed, 8 insertions(+), 15 deletions(-) diff --git a/applications/main/ibutton/scenes/ibutton_scene_save_success.c b/applications/main/ibutton/scenes/ibutton_scene_save_success.c index 8b16d2929..7632a4909 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_save_success.c +++ b/applications/main/ibutton/scenes/ibutton_scene_save_success.c @@ -9,9 +9,7 @@ void ibutton_scene_save_success_on_enter(void* context) { iButton* ibutton = context; Popup* popup = ibutton->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); - + popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); popup_set_callback(popup, ibutton_scene_save_success_popup_callback); popup_set_context(popup, ibutton); popup_set_timeout(popup, 1500); diff --git a/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c b/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c index 35f515989..a5e5c8977 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c @@ -4,8 +4,7 @@ void infrared_scene_edit_rename_done_on_enter(void* context) { InfraredApp* infrared = context; Popup* popup = infrared->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); popup_set_callback(popup, infrared_popup_closed_callback); popup_set_context(popup, context); diff --git a/applications/main/infrared/scenes/infrared_scene_learn_done.c b/applications/main/infrared/scenes/infrared_scene_learn_done.c index b4eb38331..959424393 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn_done.c +++ b/applications/main/infrared/scenes/infrared_scene_learn_done.c @@ -4,12 +4,11 @@ void infrared_scene_learn_done_on_enter(void* context) { InfraredApp* infrared = context; Popup* popup = infrared->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - if(infrared->app_state.is_learning_new_remote) { + popup_set_icon(popup, 48, 6, &I_DolphinDone_80x58); popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); } else { - popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); } popup_set_callback(popup, infrared_popup_closed_callback); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c index 52aefa848..7247de3ad 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c @@ -7,8 +7,7 @@ void lfrfid_scene_save_success_on_enter(void* context) { // Clear state of data enter scene scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveData, 0); - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); popup_set_context(popup, app); popup_set_callback(popup, lfrfid_popup_timeout_callback); popup_set_timeout(popup, 1500); diff --git a/applications/main/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c index 0cb26c0d4..e5bcd4f2d 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc/scenes/nfc_scene_save_success.c @@ -10,8 +10,7 @@ void nfc_scene_save_success_on_enter(void* context) { // Setup view Popup* popup = nfc->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); + popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); popup_set_timeout(popup, 1500); popup_set_context(popup, nfc); popup_set_callback(popup, nfc_scene_save_success_popup_callback); diff --git a/applications/main/subghz/scenes/subghz_scene_save_success.c b/applications/main/subghz/scenes/subghz_scene_save_success.c index 40ade5a53..725a504df 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_success.c +++ b/applications/main/subghz/scenes/subghz_scene_save_success.c @@ -11,8 +11,7 @@ void subghz_scene_save_success_on_enter(void* context) { // Setup view Popup* popup = subghz->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); + popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); popup_set_timeout(popup, 1500); popup_set_context(popup, subghz); popup_set_callback(popup, subghz_scene_save_success_popup_callback); diff --git a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c index 481ba6d5c..b7ed63f63 100644 --- a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c +++ b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c @@ -10,7 +10,7 @@ void bt_settings_scene_forget_dev_success_on_enter(void* context) { BtSettingsApp* app = context; Popup* popup = app->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_icon(popup, 48, 6, &I_DolphinDone_80x58); popup_set_header(popup, "Done", 14, 15, AlignLeft, AlignTop); popup_set_timeout(popup, 1500); popup_set_context(popup, app); From 94cdaf20a2264a554cd1df2e233f223e2a9dc82f Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 1 Dec 2023 17:24:43 +0300 Subject: [PATCH 004/110] New success dolphin image added --- assets/icons/iButton/DolphinSuccess_91x55.png | Bin 0 -> 930 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/icons/iButton/DolphinSuccess_91x55.png diff --git a/assets/icons/iButton/DolphinSuccess_91x55.png b/assets/icons/iButton/DolphinSuccess_91x55.png new file mode 100644 index 0000000000000000000000000000000000000000..80caeb203c69add5e5786f576daeb3b018b1c859 GIT binary patch literal 930 zcmV;T16}-yP)a80tk`0v%FYt{QS^;XijtOsVUD?#;+`c<*fIT3&TD?M& z)R06pD<=<1yq5Nwf~f2rMN`RW@xLABnmu1zf@(zLuCU@6K;_KkNePA;OOnm`YL5b? zN2t4s&U7U^vAMgIRkqiKc*{aXbz{Ogp;&7-OLmqEf$vo$7-RLCrSa?mNx6`y!;Df( z6!Bb~-MqCLF2$eY9%M_3j&u!?2c+eqEmo5o!--5QA2=SVY);XUHf@(^tE%uA=^F4| zrp1NhD1IK~*dB?Q}$eEWlXi^hqK5WNV0cpw&j+> z2}`joYeqoo2_oW=Wn?b2tL)VhkwI*PJBi9IMcFu3E*WX;%y99JSV~55t#A0nDaB}EWW!Q%O4%8>eTYkN)$EF$q_;L(K*hAa z2hqnE>{mV&?4AV?IYvM6qu{F96*eI9?jk+0;R}QLx7otB*2Mo*dJDlBjSja7cs(mO zYRx|7yE#C=O?`f{(cwHl_R}0xpMA@nWNxI#8b;jNA{Bje*34|Bd+T}@ zRAnDY!qFg5b3OC9n9-_k4Ou^H=NP>axIysFt&S4Pu7oUAw`Qo>^L_aHKYUj9gKVu+ z{C1^dkwxQ=>|32;6>xX8G)K>z>% literal 0 HcmV?d00001 From 59e797b3122af0fa6e4617717140625846a0db1e Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 1 Dec 2023 17:25:00 +0300 Subject: [PATCH 005/110] Success scene image replaced --- .../nfc/scenes/nfc_scene_mf_classic_write_initial_success.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_success.c index acb75cd2e..100c5c431 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_success.c @@ -12,8 +12,8 @@ void nfc_scene_mf_classic_write_initial_success_on_enter(void* context) { notification_message(instance->notifications, &sequence_success); Popup* popup = instance->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Successfully\nwritten", 13, 22, AlignLeft, AlignBottom); + popup_set_header(popup, "Success!", 75, 10, AlignLeft, AlignTop); + popup_set_icon(popup, 0, 9, &I_DolphinSuccess_91x55); popup_set_timeout(popup, 1500); popup_set_context(popup, instance); popup_set_callback(popup, nfc_scene_mf_classic_write_initial_success_popup_callback); From 7554e7bedbbce8d3e63eb94a97cc83885a6317d9 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 1 Dec 2023 17:29:32 +0300 Subject: [PATCH 006/110] Changed image and text for update initial scene --- .../nfc/scenes/nfc_scene_mf_classic_update_initial_success.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial_success.c index 02e307b01..2e0ada0da 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial_success.c @@ -12,8 +12,8 @@ void nfc_scene_mf_classic_update_initial_success_on_enter(void* context) { notification_message(instance->notifications, &sequence_success); Popup* popup = instance->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Updated!", 11, 20, AlignLeft, AlignBottom); + popup_set_icon(popup, 48, 6, &I_DolphinDone_80x58); + popup_set_header(popup, "Updated", 11, 20, AlignLeft, AlignBottom); popup_set_timeout(popup, 1500); popup_set_context(popup, instance); popup_set_callback(popup, nfc_scene_mf_classic_update_initial_success_popup_callback); From fa04e36df2c028963559b45176418192c6fbf2e1 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 1 Dec 2023 17:41:08 +0300 Subject: [PATCH 007/110] Image and text adjusted for "Original restored" scene --- applications/main/nfc/scenes/nfc_scene_restore_original.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_restore_original.c b/applications/main/nfc/scenes/nfc_scene_restore_original.c index 612e6041e..3a47ce8c3 100644 --- a/applications/main/nfc/scenes/nfc_scene_restore_original.c +++ b/applications/main/nfc/scenes/nfc_scene_restore_original.c @@ -10,8 +10,8 @@ void nfc_scene_restore_original_on_enter(void* context) { // Setup view Popup* popup = nfc->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Original file\nrestored", 13, 22, AlignLeft, AlignBottom); + popup_set_icon(popup, 48, 6, &I_DolphinDone_80x58); + popup_set_header(popup, "Original file\nrestored", 5, 22, AlignLeft, AlignBottom); popup_set_timeout(popup, 1500); popup_set_context(popup, nfc); popup_set_callback(popup, nfc_scene_restore_original_popup_callback); From f151d3be013b5f9b579b85d2193f8734691df6fb Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 1 Dec 2023 18:13:14 +0300 Subject: [PATCH 008/110] Removed old DolphinNice_96x59.png image --- assets/icons/iButton/DolphinNice_96x59.png | Bin 2459 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 assets/icons/iButton/DolphinNice_96x59.png diff --git a/assets/icons/iButton/DolphinNice_96x59.png b/assets/icons/iButton/DolphinNice_96x59.png deleted file mode 100644 index a299d3630239b4486e249cc501872bed5996df3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2459 zcmbVO3s4i+8V(M(gEFORwSrA`4O0uPn|M|5y* zB*aMDxC&7(gP9JN;POOi-9khrC>Z9YJs2U!LnVcQEEC0fDtKo&ILlzb30%M}3J^;~ zv7RzcsilOs4Mq@tD*&R;!LMSk2A~{(`HK9|hQBqEX)3sQr9Je6SZU*F-^fD-p+~Hs; zHLkO%v?>ZoxEv+F#whudr%615FkA0DYR0tMEo}3OOY#xecLWe>xV?u5KtSmC^ z7)Fmj6gjfKstiEV-*Cxbbb+&rRWuI_rBJ)ybs_f1Rn&f2>q3pYwI^|J(hdn{j{0EZIm_F zpIyIWLsRUgOItR-dUbVd|6Zo=_BU_Tj4|{{jxO#=JH4o8er(5{!nZD_j4}MH&zh~9 zVLC~y(0-D6GO0ghZD8BYzP?o{>22~lT6^d@X{SwQ8vrNY-PPIMajIwC)`s14Ep72@ zeq7YOzM`?U{+W)ocXBr`eSOcpk?Rxc=ou5&)fWW|pD};-Z0mvk9}=&`Rb&y<77W~a z(>6YM;6Y5aIU~JKZ}mQZynKHiSTQ#Bczn@&jTiN^?vPJ(jhm7cXLx0oum5P$`TceG zU+wR;OO^)8CVlnM)5p$CO&e94KJt>HccCaHGusmW_b`T6m| z-R6V6Db1pErTot?^d22ojm+2>_)FbD`_+WbDGMx9f@hO27maS2`csiV(D&Fs`PS2& zvrq18du_&zXID(!KIxsU$)iuTYuZ?zmYiP&n&i@Be{IdbS-jA2c0QAlu5NXQv_0K< z3Hvs4eeu6B7yD&CNT~gIkMV&UkRU=V!iQ(+_(O&u^ah$+s{_yn(yBYeD40HeU{xGsIT6W Zfq!wOp!Q Date: Mon, 4 Dec 2023 21:17:45 +0300 Subject: [PATCH 009/110] New image for LFRFID scene --- applications/main/lfrfid/scenes/lfrfid_scene_write_success.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_write_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_write_success.c index 52e30d6b6..78ba48137 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_write_success.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_write_success.c @@ -4,8 +4,8 @@ void lfrfid_scene_write_success_on_enter(void* context) { LfRfid* app = context; Popup* popup = app->popup; - popup_set_header(popup, "Successfully\nwritten!", 94, 3, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57); + popup_set_header(popup, "Success!", 75, 10, AlignLeft, AlignTop); + popup_set_icon(popup, 0, 9, &I_DolphinSuccess_91x55); popup_set_context(popup, app); popup_set_callback(popup, lfrfid_popup_timeout_callback); popup_set_timeout(popup, 1500); From 7af6a46c8f41637375ea82ff106bebc6553d325a Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Mon, 4 Dec 2023 21:17:56 +0300 Subject: [PATCH 010/110] Removed unused image --- assets/icons/RFID/RFIDDolphinSuccess_108x57.png | Bin 2681 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 assets/icons/RFID/RFIDDolphinSuccess_108x57.png diff --git a/assets/icons/RFID/RFIDDolphinSuccess_108x57.png b/assets/icons/RFID/RFIDDolphinSuccess_108x57.png deleted file mode 100644 index 34199910945376f054daa0c1738d7e64dc410421..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2681 zcmcImeN+=y9!+ao5u{4RRaA5sx(ExC`N$-bj3$_n$VUkvvWQeyCX-2+CCP+jAc4io zTCG?Mt{#hG!Ga&HhzErAqZB!|3a)DvrMRvHWox_DA|h?~cy_C;?gRq5d#vj}n{y`f zW^&*C-FJU?-ehB1N_?RIEPs(m6quNxO&87<;ZXQJFMO|vU*0dACfO5~J4K>^Y2M>G z(a!3bBGF5=Y(^HJrB5bl&MKyioPiO$t#$z|5-p5%+bKGa;Q<3yE5Ey~* zc}h_2EeK@k(||b6!2mKb0?`P90fa(~%5YqU!~htAAuu9^Q4B(5B!ZJD0r)`AD7TI{p4cVOGV+>lxNjq3O z&vG`v%Saix0$vFUN=KJqwU5)CWtj)-|oKapyz6p$$;u$3aUm19L{!RP-!Ry`D_8IeE%PGl^OyD2NiXtdW#63}s*l z1!SZo6hupL8ZyWcDI_5lb-=g@OT!CeUm7-`bPIjoeBAJ$5l8Q5+!d($ki3w0A% zr_j10-}AAQ$@h&cEHDx}lA^s?SAw*+$&3;7-DaQQ-m~c(rFG>p0_jtlKMHelCf-Fk z7`0h&`hSKC{yFhZs_^O3pRMu#N9jIW>0HWYW`vCs2EB`cy<5y^Q{eyZ*Q0)qWkxNe z+1pL0&jt-;9ydhwaaFfD_;RXU5RbgQtag7C2 zhiG(KOrnS*)EX4kX*7sj5~q_a#t}rJi_^#+n>n(QQ9*%bx71r}g zOh?Nr0V%D+vkjR^-L8r$uG*D%=0_JstSCthwRNIZ6UzYqsFat{*<}NghoNb+7R7YN z^|kN%>y`Lk?$*NL`?8^w53Bq;UQ8~MR$yhHIfmNh{(!hK6YktHA^)}ZHQ^PW@~*Xfnv zyN6~6#V@*a?tRU-Y)Q5wKX~|}3?sI6m4^BC_BFJqEC)q%r`~OT$$YnRQ_CMZ2ENIB zSl)B!q*-I%{>kmC9VctbLQkruy?m74mCYagwq{Ri;J}Z7JbcyMg8I~c&%6ipv48H( zZR>5U8+0X?JC_bM#2pJOxZWB#J^jn?bJfX{FIk83{d9;cX7x>YYDnoE^-aUI8}RgZ zIBn9citKF!AINLkL^rrTGK91fqwf0=~Vsi8CK5AM0vh)#dnRC#A`T7`eDX;tPYB~dd1 zep=o%u`*1)tI*R@76D5xM*-QB#zTG=7j%O3(`FIAIS2uN{Aln&F@9)?Dgd} zcc|l&fZy&dy)n6`u6{#l>hr|5n%Cp|4{!DxI2g=S9N<1rj_Ukn(c0 zH*)b`%3H3s_r2=MII*qfW8LLsxV-L~J2pzaJNj2i-vtbLR7>;!-db4@Os~B@@7zkZ zXT=LO^0)h?M_*gE=d1MHA9+sji=XqXuRWFCB`NV>4_bG+XE!Au&4Dh5v>)+5xA%Q< zt!wkCD*1qFcbm2QU-Ns4j%yP)AGv=iHmi5LIIl#~eyjM6MEh_+V&0tvJ5=S=dJOTy~%6^nwZGp5xyf1Iy3Yx}id-~MjWmBzE@l0x=}tLFY`$&$eh z_Sk*5-$8 Date: Mon, 4 Dec 2023 23:59:25 +0300 Subject: [PATCH 011/110] New UI image added to assets --- .../icons/Interface/WarningDolphinFlip_45x42.png | Bin 0 -> 1437 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/icons/Interface/WarningDolphinFlip_45x42.png diff --git a/assets/icons/Interface/WarningDolphinFlip_45x42.png b/assets/icons/Interface/WarningDolphinFlip_45x42.png new file mode 100644 index 0000000000000000000000000000000000000000..2ba54afce0249303787fb3d94a78cc167a81a253 GIT binary patch literal 1437 zcmeAS@N?(olHy`uVBq!ia0vp^x+tIX_n~5u`@1BDVmjn}NZ`zM>#8IXksPAt^OIGtXA( z{qFrr3YjUkO5vuy2EGN(sTr9bRYj@6RemAKRoTgwDN6Qs3N{s1Km&49OA-|-a&z*E zttxDlz~)*3*&tzkB?YjOl5ATgh@&EW0~DO|i&7QL^$c~B4Gatv%q{g&Qxc7mjMEa6 zbrg&Yj12V+fyi9f(A>(%*vimS0Sc6W78a$XSp~VcL9GMwY?U%fN(!v>^~=l4^~#O) z@{7{-4J|D#^$m>ljf`}GDs+o0^GXscbn}XpVJ5hw7AF^F7L;V>=P7_pOiaozEwNPs zIu_!K+yY-;xWReF(69oAntnxMfxe-hfqrf-$ZKHL#U(+h2xnkbT^v$bkg6Y)TAW{6 zlnjiLG-a4(VDRC$2&53`8Y`Fl?$S+VZGS)Lx(C|%6&ddXeXo5l)>e$qx%(B!Jx1#)91#s|KWnyuHfvcmlo299R znSrq(*!kwBrk1WoW~Q!gE(Qk1mP$~)DOkJ?)oY1UuRhQ*`k=T)iffn@Wcz` zz>|M!9x%-p0TcJDoOQE-Iq{~ai(^QH`_*ZU>zWmKTucA|KmWe+?mErbXs(XSlV`YU zyj{3y=hyt?pBvV_R?6ew^D+M8uNu3qtmT_y-D0L)TyCc0dsA%UJkv=5Rzh;RJXOUd zb2IbOTqF$GpKcbJdrqLVzGd1T*X2+9*4{lY#C9V4>K2V9OE2i`>{wIr%jf)?BJJZd zuUTJdQogkH&a9}lvA4LA6npx)qIWK?x%%_%t!Ix}6uLep6h2dsS$*~Ev(@QR+>tKg z{Rx5VCNfp6n;I+CU0M0%6tiXxoBrH_wi@r8w!N3b)U#YQ?77X3J+inwuOh!a;>s!M zv#A>UI^rh96)w2m$Hn}af3o_`pcBH`g5Q$P&bQHDxm}W5pZ!?$r-&Js9`F?M>z7Y^ zY$~^~+n{bs1@D!OSqrT8+&A~yr*>6)e(dx~*IxLhbfzrnPjRGZ^@Z|QqP|R zTf{vU*uQ$uw_jB|PcZzAILGiaHBNU)cG13w&3AXCSuJ$kaL2{#H7|p$nykgUeK8Iy zEju&pn3Sd&9GD@pm18L<>(i^uuF=;{N93ug){1WBn;h+#e&AT0TJLc_#>&d$ZvF9E zzJWrXr!3AsoxANwWh&>=#qMTJV%skmUV2;@?^2MR`M%R;)nyx{?bH9g`?l#1bH%|O Uzg^}hzX270p00i_>zopr0LnWHWB>pF literal 0 HcmV?d00001 From d113bbf4dd9dcd119ae81f0c93cc9307cc43afea Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 5 Dec 2023 00:00:03 +0300 Subject: [PATCH 012/110] Replaced warning dolphin on mf_classic write initial fail scene --- .../main/nfc/scenes/nfc_scene_mf_classic_write_initial_fail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_fail.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_fail.c index f85e5a80c..4d4367ec8 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_fail.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_fail.c @@ -16,7 +16,7 @@ void nfc_scene_mf_classic_write_initial_fail_on_enter(void* context) { notification_message(instance->notifications, &sequence_error); - widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48); + widget_add_icon_element(widget, 83, 22, &I_WarningDolphinFlip_45x42); widget_add_string_element( widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!"); widget_add_string_multiline_element( From 278ae51d73b39898cfbbdaa1432e30a7a7c64288 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 5 Dec 2023 00:16:24 +0300 Subject: [PATCH 013/110] Removed old image --- assets/icons/Dolphin/DolphinCommon_56x48.png | Bin 1416 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 assets/icons/Dolphin/DolphinCommon_56x48.png diff --git a/assets/icons/Dolphin/DolphinCommon_56x48.png b/assets/icons/Dolphin/DolphinCommon_56x48.png deleted file mode 100644 index 089aaed83507431993a76ca25d32fdd9664c1c84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1416 zcmaJ>eNYr-7(dh;KXS5&nWVIBjS_NizYg|x=Pr^vz*7zxJO|P-dw2IeZq?gec9-rD zoPZchQ_6}yP{Slc4I!!28K==nodOJ_nsCY-(wOq2uZbLx!rlYU{KIi)_Wj!D_j`WN z^FGgREXdEDF)ewT&1Re7Tj(uBvlG44lnH3;I%IzsO|z`*Vr!`uv?9QOwgs{#Ld+Ki zC9n_zxxBOkx@@+IwMwAaD)#3Ik`}gun2kLe))Crfb7e+#AgzHGCc+X$b>qJuIf`S7 z?8b}I{ghw#z>uiaLknQh@LJUrqHcVYS3v97F^OZN zCe|7^J|?QzUx0Zu17e(=CM1fYFpjtLk|a4~$g}e?hGH0!VoBOT&<=s(1ct%J9~?O} z$)jW_dkX9yTX~%W*i_IM%0{ z7EmP^_pKn`<5>E(SixgJU};7`)7Hidp&+DLnizsebUk}_-GfgbN^il9b`v)f+ z{o5Zry)d<7`fHQ^uw_;+x>mcPw0&8iW69x{k92O{Q}`yFdH=5d$pbf49w1&NS)G+vhr6y}5TMsofQirRDUmKilk5=(KGouJ{H9hW=$X zgi;)vI!jl!_4H3jD(?Jz=8By|i47I&tKA1y9{nfp;_|FxKBDNWp{hN9hJ1nU?z%J6 z?>UxyzWvO}Pgc~rCZ#5%Eq+_hNS~bBdiGlT&f%%e`hHjSySR2=JuK2^+%;$R3#Wz~ z=e_mfqW23bPa0fhe)HdE5+GelU&!jS3ckUZOQ)CC5?mo zo=tzG_4|RuvPUO|mhCwA>y)1c%SWC%a4?a-x|J*?ch~+n=R7o@>p6J2dE=$stKZmK z-xoTRwET2^Wu)&1U7!Ebw!!D?x`xwQX3pMnrRwCT?`4GHt4&?|cIiI{_^XYp-np>6 xE^lPSXzOYCC4X`6tl@OB1M5_S7jml-Y~(TPp{aTIejNKZ`m*!Atyxdk{0EAy49frj From 12180ba70784f65575ca5bcff65f0e8b99f7307a Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 5 Dec 2023 00:19:47 +0300 Subject: [PATCH 014/110] Changed image on scenes to a new one --- applications/main/lfrfid/scenes/lfrfid_scene_write.c | 4 ++-- .../nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c | 2 +- .../main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c | 2 +- .../main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c | 2 +- applications/main/subghz/scenes/subghz_scene_receiver_info.c | 2 +- applications/main/subghz/scenes/subghz_scene_show_error_sub.c | 2 +- applications/main/subghz/scenes/subghz_scene_show_only_rx.c | 2 +- applications/main/subghz/subghz_i.c | 2 +- applications/services/loader/loader.c | 2 +- .../scenes/storage_settings_scene_benchmark.c | 2 +- .../scenes/storage_settings_scene_format_confirm.c | 2 +- .../scenes/storage_settings_scene_formatting.c | 2 +- .../storage_settings/scenes/storage_settings_scene_sd_info.c | 2 +- .../scenes/storage_settings_scene_unmounted.c | 2 +- 14 files changed, 15 insertions(+), 15 deletions(-) diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_write.c b/applications/main/lfrfid/scenes/lfrfid_scene_write.c index b7faed69f..f6e762e4d 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_write.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_write.c @@ -57,7 +57,7 @@ bool lfrfid_scene_write_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(app->scene_manager, LfRfidSceneWriteSuccess); consumed = true; } else if(event.event == LfRfidEventWriteProtocolCannotBeWritten) { - popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48); + popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42); popup_set_header(popup, "Error", 64, 3, AlignCenter, AlignTop); popup_set_text(popup, "This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop); notification_message(app->notifications, &sequence_blink_start_red); @@ -65,7 +65,7 @@ bool lfrfid_scene_write_on_event(void* context, SceneManagerEvent event) { } else if( (event.event == LfRfidEventWriteFobCannotBeWritten) || (event.event == LfRfidEventWriteTooLongToWrite)) { - popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48); + popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42); popup_set_header(popup, "Still trying to write...", 64, 3, AlignCenter, AlignTop); popup_set_text( popup, diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c index 991c956c1..c3fb92bee 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c @@ -11,7 +11,7 @@ void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { // Setup view Popup* popup = instance->popup; - popup_set_icon(popup, 72, 16, &I_DolphinCommon_56x48); + popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42); popup_set_header(popup, "Key already exists!", 64, 3, AlignCenter, AlignTop); popup_set_text( popup, diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c index 50025048a..a879985bc 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c @@ -16,7 +16,7 @@ void nfc_scene_mf_classic_wrong_card_on_enter(void* context) { notification_message(instance->notifications, &sequence_error); - widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); + widget_add_icon_element(widget, 83, 22, &I_WarningDolphinFlip_45x42); widget_add_string_element( widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card"); widget_add_string_multiline_element( diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 6be051ced..855049d65 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -40,7 +40,7 @@ void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop); dialog_ex_set_text( dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop); - dialog_ex_set_icon(dialog_ex, 73, 20, &I_DolphinCommon_56x48); + dialog_ex_set_icon(dialog_ex, 83, 22, &I_WarningDolphinFlip_45x42); dialog_ex_set_center_button_text(dialog_ex, "OK"); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 7180bb3a4..08d4caecf 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -93,7 +93,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { subghz); } } else { - widget_add_icon_element(subghz->widget, 37, 15, &I_DolphinCommon_56x48); + widget_add_icon_element(subghz->widget, 83, 22, &I_WarningDolphinFlip_45x42); widget_add_string_element( subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse."); } diff --git a/applications/main/subghz/scenes/subghz_scene_show_error_sub.c b/applications/main/subghz/scenes/subghz_scene_show_error_sub.c index 113e7ae74..0de48c442 100644 --- a/applications/main/subghz/scenes/subghz_scene_show_error_sub.c +++ b/applications/main/subghz/scenes/subghz_scene_show_error_sub.c @@ -11,7 +11,7 @@ void subghz_scene_show_error_sub_on_enter(void* context) { // Setup view Popup* popup = subghz->popup; - popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48); + popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42); popup_set_header(popup, furi_string_get_cstr(subghz->error_str), 14, 15, AlignLeft, AlignTop); popup_set_timeout(popup, 1500); popup_set_context(popup, subghz); diff --git a/applications/main/subghz/scenes/subghz_scene_show_only_rx.c b/applications/main/subghz/scenes/subghz_scene_show_only_rx.c index 1907c4192..3522bf8aa 100644 --- a/applications/main/subghz/scenes/subghz_scene_show_only_rx.c +++ b/applications/main/subghz/scenes/subghz_scene_show_only_rx.c @@ -21,7 +21,7 @@ void subghz_scene_show_only_rx_on_enter(void* context) { popup_set_header(popup, header_text, 63, 3, AlignCenter, AlignTop); popup_set_text(popup, message_text, 0, 17, AlignLeft, AlignTop); - popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48); + popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42); popup_set_timeout(popup, 1500); popup_set_context(popup, subghz); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index c03efe5e5..4358b164d 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -70,7 +70,7 @@ void subghz_dialog_message_show_only_rx(SubGhz* subghz) { dialog_message_set_header(message, header_text, 63, 3, AlignCenter, AlignTop); dialog_message_set_text(message, message_text, 0, 17, AlignLeft, AlignTop); - dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17); + dialog_message_set_icon(message, &I_WarningDolphinFlip_45x42, 83, 22); dialog_message_show(dialogs, message); dialog_message_free(message); diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 29ec86ac6..158b95de6 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -55,7 +55,7 @@ LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const DialogMessage* message = dialog_message_alloc(); dialog_message_set_header(message, "Update needed", 64, 3, AlignCenter, AlignTop); dialog_message_set_buttons(message, NULL, NULL, NULL); - dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17); + dialog_message_set_icon(message, &I_WarningDolphinFlip_45x42, 83, 22); dialog_message_set_text( message, "Update firmware\nto run this app", 3, 26, AlignLeft, AlignTop); dialog_message_show(dialogs, message); diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c index a5bf1b9d3..e734c78e0 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c @@ -125,7 +125,7 @@ void storage_settings_scene_benchmark_on_enter(void* context) { view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx); if(sd_status != FSE_OK) { - dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48); + dialog_ex_set_icon(dialog_ex, 83, 22, &I_WarningDolphinFlip_45x42); dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_text( dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c b/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c index 8af065bf8..862f55a46 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_format_confirm.c @@ -14,7 +14,7 @@ void storage_settings_scene_format_confirm_on_enter(void* context) { FS_Error sd_status = storage_sd_status(app->fs_api); if(sd_status == FSE_NOT_READY) { - dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48); + dialog_ex_set_icon(dialog_ex, 83, 22, &I_WarningDolphinFlip_45x42); dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_text( dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c b/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c index df5e3cc17..f107aacea 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_formatting.c @@ -47,7 +47,7 @@ void storage_settings_scene_formatting_on_enter(void* context) { dialog_ex_set_text( dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter); } else { - dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48); + dialog_ex_set_icon(dialog_ex, 83, 22, &I_WarningDolphinFlip_45x42); dialog_ex_set_header(dialog_ex, "Format\ncomplete!", 14, 15, AlignLeft, AlignTop); } dialog_ex_set_center_button_text(dialog_ex, "OK"); diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c index 81c786d0c..aa9662a71 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c @@ -19,7 +19,7 @@ void storage_settings_scene_sd_info_on_enter(void* context) { dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_sd_info_dialog_callback); if(sd_status != FSE_OK) { - dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48); + dialog_ex_set_icon(dialog_ex, 83, 22, &I_WarningDolphinFlip_45x42); dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_text( dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c b/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c index 33bb95522..86398b1c9 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c @@ -42,7 +42,7 @@ void storage_settings_scene_unmounted_on_enter(void* context) { } dialog_ex_set_center_button_text(dialog_ex, "OK"); - dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48); + dialog_ex_set_icon(dialog_ex, 83, 22, &I_WarningDolphinFlip_45x42); dialog_ex_set_context(dialog_ex, app); dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_unmounted_dialog_callback); From 18ea05edeeec8573edc9fa91cb32ad1ff82a3c86 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 5 Dec 2023 14:33:47 +0300 Subject: [PATCH 015/110] New dolphin mafia image --- assets/icons/iButton/DolphinMafia_119x62.png | Bin 0 -> 2037 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/icons/iButton/DolphinMafia_119x62.png diff --git a/assets/icons/iButton/DolphinMafia_119x62.png b/assets/icons/iButton/DolphinMafia_119x62.png new file mode 100644 index 0000000000000000000000000000000000000000..0122a56cca52157fcbd0d77934a1d6c6bbcbcdef GIT binary patch literal 2037 zcmbVNdsGu=7LOp7VxT>uZEFc0ZyC5)0CLxeyLNb^TSWv+S zx@g^%WktaU74`%U(zt>wRJ5?7qOe_A%no2q+WH ztrS2h6HvBuq8L$HA)2P#Xwso^rs#O7DMJd&D8cK2AS0hJphj^7FsfA=J>Mvxytd0H zWcx9l0=!niGX#`3q!OZH03oJB0hq=Fr3?lWfCwp&%i_T>1VI4+i@{>k8C*Jx1G3nB z4#Z~$0`m`r@Til?`LUu6^ZtmPfRcveT0Wg_Fc@eCHVxA$=u8-f=?oT~#R3TpP@k>A z5hJM4`z=@yp?axKsl}C;2C!R1Bv=+Mpb%`|grU|(MZGnw(a$G~NE_XVXz5HEgRWNF zV|%Tw$79j|(s-w~K0aHE(qmCQmZg&tHIe%*fQkJ5vLm}9!G^zCrz8r4s6?1FOO0x9 zu}DB6ZfG*4jE|xmSSn+~APa%yU?7*x03|Fo3PMtt12ZLDRKk`l*m)N|P{iYgZD8>r zZm5XK3=fBS91)MrQDs7bnzIbTIhtB zGz`b|X_yvZacB&H8ih!e8vBXAy-II_7NI)jPE@u*hpBNod@fzALzRdy0pbqowJ!* zhm`l8o4zWnS(jn?k-F|`NoLSNfv457y8+NfeA!*x?O4|LNgptLZ6rJ7BTDV+G`C$d z`kAMG16Krx9WR^Yp}B*$W-2t?m8$M4dGSFTZSk0SQHa*3Dmbx**;Kpdl7iVazTexm zM`ONnF4A<{>wv=&fB!>2xce=xyx*ZBN$zWvcIq!eeV5kG3ViFg;6k&!}82 zbbJvx)IG%gm9Vv}i{4lC2hu$l%JaL6`m|3C7H>`)+W1{$VM2XNTjR=(3jgWkq?aM& zsmA=hSDq_K<>l@^wi9_zY=KQY->TjeZJp2hGbtlqAuG*V-v;IT>MO~UO@6V8nRC3! zWfxnvOipBa%m3+j=)(_BdxThcF@-#q;~1_H)#eS66KMA>!lv zABE+98nH7h_wI7%1Ll+Pg?#FDy{LNW*}UFczpJV^5_y)M^JQ8Nn% z_STrYUXm3L%Kpqhd}hb?ZP~wX_gGPSK3`4}JW(`u?)%5K$9PX~%30?_hpXg{qX|jd zjyr25ExzqVC%!-K;80>#H4H4Vfr3-RG1VPi=E(ZKE%Opr4vsHmTyd@wj)#0q5^V zO??xIW!MO{DS6ejwtAP-ng0IMbCtH)FHLaPbJV4B>+a#(gM%GoYX&Q1psB^y?>7oY z?9vQ39L;2xIduHiD|Jg~ty6!kaO?+_2@-XF;Se^6UxKeD?zPp2xKrB9mTzOp?xWnl zN4RurimoR$rJD->#<%=2YbG&etatT zn8FG~dmA+S(ud|IKTBu(_MG1rP@Hq*#iz84EZSTN8NR$*l~t;?S{@07Emx_p9+xa{ vcvM#IF=F-qEZF^3{BW(CrPV9*XRlP!N%HojB5X^m{YNYgj~3O1rSAC;dI3PE literal 0 HcmV?d00001 From 064c60e52ebad3406d8c680f910a70cdcd4c7a97 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 5 Dec 2023 14:34:14 +0300 Subject: [PATCH 016/110] Replaced dolphin mafia image to a new one --- .../main/ibutton/scenes/ibutton_scene_delete_success.c | 4 +--- .../main/infrared/scenes/infrared_scene_edit_delete_done.c | 4 +--- applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c | 3 +-- applications/main/nfc/scenes/nfc_scene_delete_success.c | 3 +-- applications/main/subghz/scenes/subghz_scene_delete_success.c | 3 +-- .../scenes/desktop_settings_scene_pin_disable.c | 3 +-- 6 files changed, 6 insertions(+), 14 deletions(-) diff --git a/applications/main/ibutton/scenes/ibutton_scene_delete_success.c b/applications/main/ibutton/scenes/ibutton_scene_delete_success.c index 9ff165e4a..3ecfe3051 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_delete_success.c +++ b/applications/main/ibutton/scenes/ibutton_scene_delete_success.c @@ -9,9 +9,7 @@ void ibutton_scene_delete_success_on_enter(void* context) { iButton* ibutton = context; Popup* popup = ibutton->popup; - popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); - + popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62); popup_set_callback(popup, ibutton_scene_delete_success_popup_callback); popup_set_context(popup, ibutton); popup_set_timeout(popup, 1500); diff --git a/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c b/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c index 9205db4c4..9c4322d75 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c @@ -4,9 +4,7 @@ void infrared_scene_edit_delete_done_on_enter(void* context) { InfraredApp* infrared = context; Popup* popup = infrared->popup; - popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); - + popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62); popup_set_callback(popup, infrared_popup_closed_callback); popup_set_context(popup, context); popup_set_timeout(popup, 1500); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c index f940b9bd4..1918d9033 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c @@ -4,8 +4,7 @@ void lfrfid_scene_delete_success_on_enter(void* context) { LfRfid* app = context; Popup* popup = app->popup; - popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62); popup_set_context(popup, app); popup_set_callback(popup, lfrfid_popup_timeout_callback); popup_set_timeout(popup, 1500); diff --git a/applications/main/nfc/scenes/nfc_scene_delete_success.c b/applications/main/nfc/scenes/nfc_scene_delete_success.c index f0c22eec4..fc66233f5 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete_success.c +++ b/applications/main/nfc/scenes/nfc_scene_delete_success.c @@ -10,8 +10,7 @@ void nfc_scene_delete_success_on_enter(void* context) { // Setup view Popup* popup = nfc->popup; - popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62); popup_set_timeout(popup, 1500); popup_set_context(popup, nfc); popup_set_callback(popup, nfc_scene_delete_success_popup_callback); diff --git a/applications/main/subghz/scenes/subghz_scene_delete_success.c b/applications/main/subghz/scenes/subghz_scene_delete_success.c index 4d9f33e37..65b26eb7a 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_success.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_success.c @@ -12,8 +12,7 @@ void subghz_scene_delete_success_on_enter(void* context) { // Setup view Popup* popup = subghz->popup; - popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62); popup_set_timeout(popup, 1500); popup_set_context(popup, subghz); popup_set_callback(popup, subghz_scene_delete_success_popup_callback); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c index 7fbcc3252..cab85feda 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c @@ -24,8 +24,7 @@ void desktop_settings_scene_pin_disable_on_enter(void* context) { popup_set_context(app->popup, app); popup_set_callback(app->popup, pin_disable_back_callback); - popup_set_icon(app->popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_header(app->popup, "PIN\ndeleted!", 95, 9, AlignCenter, AlignCenter); + popup_set_icon(app->popup, 0, 2, &I_DolphinMafia_119x62); popup_set_timeout(app->popup, 1500); popup_enable_timeout(app->popup); view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup); From fa146d8770317d318ed1cd911a45b4999f966362 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 5 Dec 2023 14:34:24 +0300 Subject: [PATCH 017/110] Removed DolphinMafia_115x62.png --- assets/icons/iButton/DolphinMafia_115x62.png | Bin 2504 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 assets/icons/iButton/DolphinMafia_115x62.png diff --git a/assets/icons/iButton/DolphinMafia_115x62.png b/assets/icons/iButton/DolphinMafia_115x62.png deleted file mode 100644 index 66fdb40ff2651916faed4a2ae1d564cafdbf7bcb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2504 zcmbVO3se(V8ji5Kg5ZmV3I#ewZHbsZB8b0=g#+k z_y7La$vcsnwa$(njyxXES*27&ad(Ehf@a%szx(??vFC0MMrAy=Img9%&ES885R5X2P@K{dB9p<$p?SQ()g~i~r4cNkC3JdH&i}sg6d%yza(--p8dMv@ zh!njtmnNcfH8EIj8V2M1)j>d@3E>C~1d9SDLpsSICOLnC7va{{Z80C1fUs$Deu(uz zAWj_#gi$mBNJXF!13?Io!6J#&-(L!@03Z+o#bAI~0tqEj1oTHFGGOY%=T4*XWF$)Q z`>C_ICpkZbWsQhfoSmI5%Jvgcv`#F6VOR`8Vh9p)2qBY0vZzT&GE1fz6a<6OdLyf+ zNWjX7YNwhuAF&nut zlTM%T7{|m!I$L;81?0JCCML&7h@%LG%A_%3 zO%`|J5~~^`5=Ij!OVKeDl|G%Q$Z2^1BoRS?PpqEAscc5@GXp|_vV@$^WlbUkA?_Ok zK?n#V5acTX5fGe&s<}GAQ5OB*z!a`e&iO^CEx1S+l}^!W3g`Ur;{!N`BvZ5jW@%VH?>OF2Tk@O zPGOv@&rGEfX|lv0Cxk2gKu)ie6Af#Vr9x}>!CI+Aiv@szVry$~6u{(al2-hTBEgTzn_D^}jklllIvu1V{Q`ig6OgP|0jI zN)sVEE|=@hm?j7H6PqgYzU5==|fB0<6@J90B?N8); z?B48M`Q6&q<>QYftD|a*tJ$!0YduA;TS}(23t@i9jJ}9E&d>+O-{j}lDtd6mP7wiU?pLh0* zla-TQ!!6f>9b(>jct-Z*@vzVmEjaUp9adYyRH)W#u&{1)0G7#K8z}OOe9Z4J`?k~5 z;u#n4^?R%GdBZDjly!H8xtVMF9ud_Q|CsUp%X4BI?jMd19&&9{QqgG_a)Rz9J*BH| z$zM9cbZYA6R(n(=QYD(cO(#Aoy6CQh;hG<}_gRz&>ZIovmNuT&Z9VwM8m5pu&$kG$ zvTJ!+pA|E6E-UBtJJrv;*XaRo7|Z#x4L(qON`UQa?6`jZqnkg3XliTEuJKo%PCa~M z@WlnE3u1ZRT?c;b@m&$07PGImr1km-TQZ8*DS|rZudw{x4R!5F9=$VOt{XWj(Y>BT zd-yG`a(KJ-o0Dfs8h&U=J*C(_ z=8hNq6aC?^r7wqGy5!v`zvX@KNEDDEpXqBVXiB`Z=eNZRgGG2tG`F;x~xDn9)G1Y@4Fl28Px*E!|ivy@~-8Lx%@`DyQ}?V z4f!BGF*jl}N~1D%!=YeZY6W)9lyDw_Uq#NDJx^=CJZDD2|CF# zA7Ixt{Z7BT8@4fZgFkI{D9fJxang<$JS``+d(*81cbB@prG*c!rZ)8U4y-<__Pt)Z zZ3lJfK;Y5eZHd?A3O-!mWX3$UChhmy)r@4iKkvyz(mdTtF7?TWn4`7t4=} zZ`OLe!fHzEo3eUH7jwVD-n?Xnx$AC<-H6`;RB2iYH9UO}ROfZkPOl32mRZ%`xW#FL zD@GqK${E&#=gzidc(qkxLZ^tk7u}u0Uu|;00}}A@rq4$9xE75>Hwj!4$Nk!`)YmDg{{4HeKCy?7Z85xPzg%Peucca}QJ6#D*z!+`G0ZOj From 59e94566fd3562e5f9c955f65d5a0f5269bb588e Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 6 Dec 2023 21:17:36 +0300 Subject: [PATCH 018/110] New check symbol on completed state for detect_reader --- applications/main/nfc/views/detect_reader.c | 1 + assets/icons/NFC/check_big_20x17.png | Bin 0 -> 199 bytes 2 files changed, 1 insertion(+) create mode 100644 assets/icons/NFC/check_big_20x17.png diff --git a/applications/main/nfc/views/detect_reader.c b/applications/main/nfc/views/detect_reader.c index ebcda7caf..d832d27d6 100644 --- a/applications/main/nfc/views/detect_reader.c +++ b/applications/main/nfc/views/detect_reader.c @@ -50,6 +50,7 @@ static void detect_reader_draw_callback(Canvas* canvas, void* model) { if(m->state == DetectReaderStateDone) { canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 51, 22, AlignLeft, AlignTop, "Completed!"); + canvas_draw_icon(canvas, 20, 23, &I_check_big_20x17); } else { canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 51, 22, AlignLeft, AlignTop, "Collecting..."); diff --git a/assets/icons/NFC/check_big_20x17.png b/assets/icons/NFC/check_big_20x17.png new file mode 100644 index 0000000000000000000000000000000000000000..c74e5b1c319b11eba22a03af828c3c8f420d5dc2 GIT binary patch literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz2!3HGny7cS=Qk(@Ik;M!Q+`=Ht$S`Y;1W=H% zILO_JVcj{Imp~3nx}&cn1H;CC?mvmFKz@v;i(^OysVFTakM@=&i*yNbL<;(xkakDjK(c#1^+$-6*mTaD`o9?_&apC_PRX0}l sT&QeQUT;1nviI)7rW4P9C6@nS*ssp5V7`gf1!xb0r>mdKI;Vst04MZD2mk;8 literal 0 HcmV?d00001 From f3cbb0363d5f92cfdc563bde15dd6109908c83de Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 14 Dec 2023 11:58:59 +0300 Subject: [PATCH 019/110] Adjusted layout elements position --- applications/main/nfc/scenes/nfc_scene_detect.c | 3 ++- applications/main/nfc/scenes/nfc_scene_exit_confirm.c | 5 ++--- applications/main/nfc/scenes/nfc_scene_retry_confirm.c | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_detect.c b/applications/main/nfc/scenes/nfc_scene_detect.c index 326b1458c..1aacd6bb7 100644 --- a/applications/main/nfc/scenes/nfc_scene_detect.c +++ b/applications/main/nfc/scenes/nfc_scene_detect.c @@ -17,8 +17,9 @@ void nfc_scene_detect_on_enter(void* context) { // Setup view popup_reset(instance->popup); + popup_set_header(instance->popup, "Reading", 97, 15, AlignCenter, AlignTop); popup_set_text( - instance->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); + instance->popup, "Apply card to\nFlipper's back", 97, 27, AlignCenter, AlignTop); popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); diff --git a/applications/main/nfc/scenes/nfc_scene_exit_confirm.c b/applications/main/nfc/scenes/nfc_scene_exit_confirm.c index c024d3129..16593cc89 100644 --- a/applications/main/nfc/scenes/nfc_scene_exit_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_exit_confirm.c @@ -12,9 +12,8 @@ void nfc_scene_exit_confirm_on_enter(void* context) { dialog_ex_set_left_button_text(dialog_ex, "Exit"); dialog_ex_set_right_button_text(dialog_ex, "Stay"); - dialog_ex_set_header(dialog_ex, "Exit to NFC Menu?", 64, 11, AlignCenter, AlignTop); - dialog_ex_set_text( - dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop); + dialog_ex_set_header(dialog_ex, "Exit to NFC Menu?", 64, 0, AlignCenter, AlignTop); + dialog_ex_set_text(dialog_ex, "All unsaved data will be lost", 64, 12, AlignCenter, AlignTop); dialog_ex_set_context(dialog_ex, nfc); dialog_ex_set_result_callback(dialog_ex, nfc_scene_exit_confirm_dialog_callback); diff --git a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c index b80f1bdcc..03b0fb293 100644 --- a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c @@ -12,9 +12,8 @@ void nfc_scene_retry_confirm_on_enter(void* context) { dialog_ex_set_left_button_text(dialog_ex, "Retry"); dialog_ex_set_right_button_text(dialog_ex, "Stay"); - dialog_ex_set_header(dialog_ex, "Retry Reading?", 64, 11, AlignCenter, AlignTop); - dialog_ex_set_text( - dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop); + dialog_ex_set_header(dialog_ex, "Retry Reading?", 64, 0, AlignCenter, AlignTop); + dialog_ex_set_text(dialog_ex, "All unsaved data will be lost", 64, 12, AlignCenter, AlignTop); dialog_ex_set_context(dialog_ex, nfc); dialog_ex_set_result_callback(dialog_ex, nfc_scene_retry_confirm_dialog_callback); From 94e8e5d4983ea2488e4421f85e5f4842c6b84937 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 14 Dec 2023 13:04:42 +0300 Subject: [PATCH 020/110] Removed second switching to popup view in order to achieve control in support callbacks In general now we show generic scene and after that in on_enter callback we can redefine it for particular protocol --- .../main/nfc/helpers/protocol_support/nfc_protocol_support.c | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 87fbe9f08..eb34722bc 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -159,7 +159,6 @@ static void nfc_protocol_support_scene_read_on_enter(NfcApp* instance) { // Start poller with the appropriate callback nfc_protocol_support[protocol]->scene_read.on_enter(instance); - view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); nfc_blink_detect_start(instance); } From 1a56ce77e251058ccb02baff724ef644db9e4af5 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 14 Dec 2023 13:05:17 +0300 Subject: [PATCH 021/110] CardDetected event now also triggers on_event callback --- .../main/nfc/helpers/protocol_support/nfc_protocol_support.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index eb34722bc..390068a06 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -197,6 +197,10 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana instance->scene_manager, NfcSceneDetect); } consumed = true; + } else if(event.event == NfcCustomEventCardDetected) { + const NfcProtocol protocol = + instance->protocols_detected[instance->protocols_detected_selected_idx]; + consumed = nfc_protocol_support[protocol]->scene_read.on_event(instance, event.event); } } else if(event.type == SceneManagerEventTypeBack) { nfc_poller_stop(instance->poller); From 04e28f3e3939c2c263ff9a2397c3da2f010ebf2f Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 14 Dec 2023 13:10:37 +0300 Subject: [PATCH 022/110] Now on AuthRequest we throw CardDetected custom event --- .../nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index c4fd04c7e..820599fec 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -54,6 +54,7 @@ static NfcCommand view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); return NfcCommandStop; } else if(mf_ultralight_event->type == MfUltralightPollerEventTypeAuthRequest) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected); nfc_device_set_data( instance->nfc_device, NfcProtocolMfUltralight, nfc_poller_get_data(instance->poller)); const MfUltralightData* data = From d7b54dfa66a193f4656d548b29db1189efc64d3d Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 14 Dec 2023 13:17:23 +0300 Subject: [PATCH 023/110] Added callback for read_on_event --- .../nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 820599fec..3f8e51161 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -167,7 +167,7 @@ const NfcProtocolSupportBase nfc_protocol_support_mf_ultralight = { .scene_read = { .on_enter = nfc_scene_read_on_enter_mf_ultralight, - .on_event = nfc_protocol_support_common_on_event_empty, + .on_event = nfc_scene_read_on_event_mf_ultralight, }, .scene_read_menu = { From 69d1d5498e2fa660628b22a34178f2633fe869e2 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 14 Dec 2023 13:17:50 +0300 Subject: [PATCH 024/110] Now we show different screen while reading and unlocking --- .../mf_ultralight/mf_ultralight.c | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 3f8e51161..cefd46b45 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -90,10 +90,51 @@ static NfcCommand return NfcCommandContinue; } +enum { + NfcSceneMfUltralightReadMenuStateCardSearch, + NfcSceneMfUltralightReadMenuStateCardFound, +}; + +static void nfc_scene_read_setup_view(NfcApp* instance) { + Popup* popup = instance->popup; + popup_reset(popup); + uint32_t state = scene_manager_get_scene_state(instance->scene_manager, NfcSceneRead); + + if(state == NfcSceneMfUltralightReadMenuStateCardSearch) { + popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); + popup_set_header(instance->popup, "Unlocking", 97, 15, AlignCenter, AlignTop); + popup_set_text( + instance->popup, "Apply card to\nFlipper's back", 97, 27, AlignCenter, AlignTop); + } else { + popup_set_header(instance->popup, "Don't move", 85, 27, AlignCenter, AlignTop); + popup_set_icon(instance->popup, 12, 20, &A_Loading_24); + } + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); +} + static void nfc_scene_read_on_enter_mf_ultralight(NfcApp* instance) { + bool unlocking = + scene_manager_has_previous_scene(instance->scene_manager, NfcSceneMfUltralightUnlockWarn); + + uint32_t state = unlocking ? NfcSceneMfUltralightReadMenuStateCardSearch : + NfcSceneMfUltralightReadMenuStateCardFound; + + scene_manager_set_scene_state(instance->scene_manager, NfcSceneRead, state); + + nfc_scene_read_setup_view(instance); nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_mf_ultralight, instance); } +bool nfc_scene_read_on_event_mf_ultralight(NfcApp* instance, uint32_t event) { + if(event == NfcCustomEventCardDetected) { + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneRead, NfcSceneMfUltralightReadMenuStateCardFound); + nfc_scene_read_setup_view(instance); + } + return true; +} + static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instance) { Submenu* submenu = instance->submenu; From 4a77a236b4ec3d4864bb39bb3179cee841dc6b4a Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Mon, 18 Dec 2023 20:04:34 +0300 Subject: [PATCH 025/110] Fixed missing asstes for some scenes --- .../main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c | 2 +- .../main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c | 4 ++-- .../main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c index dff5f2781..fcfb5f2b0 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c @@ -16,7 +16,7 @@ void nfc_scene_mf_ultralight_write_fail_on_enter(void* context) { notification_message(instance->notifications, &sequence_error); - widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48); + widget_add_icon_element(widget, 83, 22, &I_WarningDolphinFlip_45x42); widget_add_string_element( widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!"); widget_add_string_multiline_element( diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c index c1fbc35ee..9726ef283 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c @@ -12,8 +12,8 @@ void nfc_scene_mf_ultralight_write_success_on_enter(void* context) { notification_message(instance->notifications, &sequence_success); Popup* popup = instance->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Successfully\nwritten", 13, 22, AlignLeft, AlignBottom); + popup_set_icon(popup, 48, 6, &I_DolphinDone_80x58); + popup_set_header(popup, "Successfully\nwritten", 5, 22, AlignLeft, AlignBottom); popup_set_timeout(popup, 1500); popup_set_context(popup, instance); popup_set_callback(popup, nfc_scene_mf_ultralight_write_success_popup_callback); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c index a225c474d..0ca765db7 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c @@ -16,7 +16,7 @@ void nfc_scene_mf_ultralight_wrong_card_on_enter(void* context) { notification_message(instance->notifications, &sequence_error); - widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); + widget_add_icon_element(widget, 83, 22, &I_WarningDolphinFlip_45x42); widget_add_string_element( widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card"); widget_add_string_multiline_element( From d5164c427fa34dfa5a251ebf2b104024f55a410e Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 19 Dec 2023 18:07:20 +0300 Subject: [PATCH 026/110] Update DolphinMafia_119x62.png --- assets/icons/iButton/DolphinMafia_119x62.png | Bin 2037 -> 1280 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/icons/iButton/DolphinMafia_119x62.png b/assets/icons/iButton/DolphinMafia_119x62.png index 0122a56cca52157fcbd0d77934a1d6c6bbcbcdef..1bbbec84ad7c1ddc9c58e5bfdbe577a07fed89f2 100644 GIT binary patch delta 1271 zcmVrDMEKdQrBqi?N|iWQr z+bI|NcQsqpFn^QV+P+#2_ZDEa;1Ps8Ik%Wl4??VIASdmuo4`# zSX7vduzw5fXKk3){;xyGKc#b_0lu#x%rfz4Vs~w*mt`!f?`q9pdw8822Cjo!x!J{& z)CcPrlCd(Bn_(Bjtz4XIxuQzDv!xFtB62FV>m^4w4=O5gcR@vkWUq3iMOQ>r*o|X( zl6IAI^6%qEOHSm@XPyup-Hz%9=a4Z5H>PylD1ZDu#IO!3B{X_cmcxC9AChrjik#%L zGel_4T|LOCERL{$R8E!jyXqNP3OBhG%C*)67E)n9%b1ZiyeRpUUu(60XN79D^gT^V z6iolx`eHy(RE0PytZsL0GWt@sC_B{~C*(UZG}W?og1ACowb8&zDpvttN%GB zJJr?u=@WyBTzpu^_blgK?i>hz*DTJe?TN)+%`w{#F}W*ZVH>S-sR{1L=1^IQYucYG zzC;f(ASoIry$aR>Zou6ftYhK67F$)(V_Q&B#go*yM!6A_9seFwa4ExUpR#jGm46b5 zs%1=&W&n!d`95{^K$1EfR~k{slPcU?L{T?x6qx002ovPDHLkV1gHQXI%gQ literal 2037 zcmbVNdsGu=7LOp7VxT>uZEFc0ZyC5)0CLxeyLNb^TSWv+S zx@g^%WktaU74`%U(zt>wRJ5?7qOe_A%no2q+WH ztrS2h6HvBuq8L$HA)2P#Xwso^rs#O7DMJd&D8cK2AS0hJphj^7FsfA=J>Mvxytd0H zWcx9l0=!niGX#`3q!OZH03oJB0hq=Fr3?lWfCwp&%i_T>1VI4+i@{>k8C*Jx1G3nB z4#Z~$0`m`r@Til?`LUu6^ZtmPfRcveT0Wg_Fc@eCHVxA$=u8-f=?oT~#R3TpP@k>A z5hJM4`z=@yp?axKsl}C;2C!R1Bv=+Mpb%`|grU|(MZGnw(a$G~NE_XVXz5HEgRWNF zV|%Tw$79j|(s-w~K0aHE(qmCQmZg&tHIe%*fQkJ5vLm}9!G^zCrz8r4s6?1FOO0x9 zu}DB6ZfG*4jE|xmSSn+~APa%yU?7*x03|Fo3PMtt12ZLDRKk`l*m)N|P{iYgZD8>r zZm5XK3=fBS91)MrQDs7bnzIbTIhtB zGz`b|X_yvZacB&H8ih!e8vBXAy-II_7NI)jPE@u*hpBNod@fzALzRdy0pbqowJ!* zhm`l8o4zWnS(jn?k-F|`NoLSNfv457y8+NfeA!*x?O4|LNgptLZ6rJ7BTDV+G`C$d z`kAMG16Krx9WR^Yp}B*$W-2t?m8$M4dGSFTZSk0SQHa*3Dmbx**;Kpdl7iVazTexm zM`ONnF4A<{>wv=&fB!>2xce=xyx*ZBN$zWvcIq!eeV5kG3ViFg;6k&!}82 zbbJvx)IG%gm9Vv}i{4lC2hu$l%JaL6`m|3C7H>`)+W1{$VM2XNTjR=(3jgWkq?aM& zsmA=hSDq_K<>l@^wi9_zY=KQY->TjeZJp2hGbtlqAuG*V-v;IT>MO~UO@6V8nRC3! zWfxnvOipBa%m3+j=)(_BdxThcF@-#q;~1_H)#eS66KMA>!lv zABE+98nH7h_wI7%1Ll+Pg?#FDy{LNW*}UFczpJV^5_y)M^JQ8Nn% z_STrYUXm3L%Kpqhd}hb?ZP~wX_gGPSK3`4}JW(`u?)%5K$9PX~%30?_hpXg{qX|jd zjyr25ExzqVC%!-K;80>#H4H4Vfr3-RG1VPi=E(ZKE%Opr4vsHmTyd@wj)#0q5^V zO??xIW!MO{DS6ejwtAP-ng0IMbCtH)FHLaPbJV4B>+a#(gM%GoYX&Q1psB^y?>7oY z?9vQ39L;2xIduHiD|Jg~ty6!kaO?+_2@-XF;Se^6UxKeD?zPp2xKrB9mTzOp?xWnl zN4RurimoR$rJD->#<%=2YbG&etatT zn8FG~dmA+S(ud|IKTBu(_MG1rP@Hq*#iz84EZSTN8NR$*l~t;?S{@07Emx_p9+xa{ vcvM#IF=F-qEZF^3{BW(CrPV9*XRlP!N%HojB5X^m{YNYgj~3O1rSAC;dI3PE From 5bff5ca40dda6c577d82593f2c168733898f4119 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 19 Dec 2023 18:44:00 +0300 Subject: [PATCH 027/110] Adjusted all the scenes with DolphinMafia image --- applications/main/ibutton/scenes/ibutton_scene_delete_success.c | 1 + .../main/infrared/scenes/infrared_scene_edit_delete_done.c | 1 + applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c | 1 + applications/main/nfc/scenes/nfc_scene_delete_success.c | 1 + applications/main/subghz/scenes/subghz_scene_delete_success.c | 1 + .../desktop_settings/scenes/desktop_settings_scene_pin_disable.c | 1 + 6 files changed, 6 insertions(+) diff --git a/applications/main/ibutton/scenes/ibutton_scene_delete_success.c b/applications/main/ibutton/scenes/ibutton_scene_delete_success.c index 3ecfe3051..6d4ca24c0 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_delete_success.c +++ b/applications/main/ibutton/scenes/ibutton_scene_delete_success.c @@ -10,6 +10,7 @@ void ibutton_scene_delete_success_on_enter(void* context) { Popup* popup = ibutton->popup; popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62); + popup_set_header(popup, "Deleted", 80, 19, AlignLeft, AlignBottom); popup_set_callback(popup, ibutton_scene_delete_success_popup_callback); popup_set_context(popup, ibutton); popup_set_timeout(popup, 1500); diff --git a/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c b/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c index 9c4322d75..651583453 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c @@ -5,6 +5,7 @@ void infrared_scene_edit_delete_done_on_enter(void* context) { Popup* popup = infrared->popup; popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62); + popup_set_header(popup, "Deleted", 80, 19, AlignLeft, AlignBottom); popup_set_callback(popup, infrared_popup_closed_callback); popup_set_context(popup, context); popup_set_timeout(popup, 1500); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c index 1918d9033..abb173a73 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c @@ -5,6 +5,7 @@ void lfrfid_scene_delete_success_on_enter(void* context) { Popup* popup = app->popup; popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62); + popup_set_header(popup, "Deleted", 80, 19, AlignLeft, AlignBottom); popup_set_context(popup, app); popup_set_callback(popup, lfrfid_popup_timeout_callback); popup_set_timeout(popup, 1500); diff --git a/applications/main/nfc/scenes/nfc_scene_delete_success.c b/applications/main/nfc/scenes/nfc_scene_delete_success.c index fc66233f5..73856c292 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete_success.c +++ b/applications/main/nfc/scenes/nfc_scene_delete_success.c @@ -11,6 +11,7 @@ void nfc_scene_delete_success_on_enter(void* context) { // Setup view Popup* popup = nfc->popup; popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62); + popup_set_header(popup, "Deleted", 80, 19, AlignLeft, AlignBottom); popup_set_timeout(popup, 1500); popup_set_context(popup, nfc); popup_set_callback(popup, nfc_scene_delete_success_popup_callback); diff --git a/applications/main/subghz/scenes/subghz_scene_delete_success.c b/applications/main/subghz/scenes/subghz_scene_delete_success.c index 65b26eb7a..d5c2b391c 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_success.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_success.c @@ -13,6 +13,7 @@ void subghz_scene_delete_success_on_enter(void* context) { // Setup view Popup* popup = subghz->popup; popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62); + popup_set_header(popup, "Deleted", 80, 19, AlignLeft, AlignBottom); popup_set_timeout(popup, 1500); popup_set_context(popup, subghz); popup_set_callback(popup, subghz_scene_delete_success_popup_callback); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c index cab85feda..43f05ec9b 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c @@ -25,6 +25,7 @@ void desktop_settings_scene_pin_disable_on_enter(void* context) { popup_set_context(app->popup, app); popup_set_callback(app->popup, pin_disable_back_callback); popup_set_icon(app->popup, 0, 2, &I_DolphinMafia_119x62); + popup_set_header(app->popup, "Deleted", 80, 19, AlignLeft, AlignBottom); popup_set_timeout(app->popup, 1500); popup_enable_timeout(app->popup); view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup); From 33136b441c18ae83b70ebe1e5b240a8f2afcc12d Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 19 Dec 2023 18:51:01 +0300 Subject: [PATCH 028/110] Scenes with save image adjusted --- .../ibutton/scenes/ibutton_scene_save_success.c | 3 ++- .../scenes/infrared_scene_edit_rename_done.c | 4 ++-- .../infrared/scenes/infrared_scene_learn_done.c | 3 ++- .../lfrfid/scenes/lfrfid_scene_save_success.c | 3 ++- .../main/nfc/scenes/nfc_scene_save_success.c | 3 ++- .../subghz/scenes/subghz_scene_save_success.c | 3 ++- assets/icons/iButton/DolphinSaved_92x58.png | Bin 0 -> 901 bytes 7 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 assets/icons/iButton/DolphinSaved_92x58.png diff --git a/applications/main/ibutton/scenes/ibutton_scene_save_success.c b/applications/main/ibutton/scenes/ibutton_scene_save_success.c index 7632a4909..6652ff7c5 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_save_success.c +++ b/applications/main/ibutton/scenes/ibutton_scene_save_success.c @@ -9,7 +9,8 @@ void ibutton_scene_save_success_on_enter(void* context) { iButton* ibutton = context; Popup* popup = ibutton->popup; - popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); + popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58); + popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom); popup_set_callback(popup, ibutton_scene_save_success_popup_callback); popup_set_context(popup, ibutton); popup_set_timeout(popup, 1500); diff --git a/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c b/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c index a5e5c8977..d7332c151 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c @@ -4,8 +4,8 @@ void infrared_scene_edit_rename_done_on_enter(void* context) { InfraredApp* infrared = context; Popup* popup = infrared->popup; - popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); - + popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58); + popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom); popup_set_callback(popup, infrared_popup_closed_callback); popup_set_context(popup, context); popup_set_timeout(popup, 1500); diff --git a/applications/main/infrared/scenes/infrared_scene_learn_done.c b/applications/main/infrared/scenes/infrared_scene_learn_done.c index 959424393..a0c605b0b 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn_done.c +++ b/applications/main/infrared/scenes/infrared_scene_learn_done.c @@ -8,7 +8,8 @@ void infrared_scene_learn_done_on_enter(void* context) { popup_set_icon(popup, 48, 6, &I_DolphinDone_80x58); popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); } else { - popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); + popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58); + popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom); } popup_set_callback(popup, infrared_popup_closed_callback); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c index 7247de3ad..2f5d5ae9f 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c @@ -7,7 +7,8 @@ void lfrfid_scene_save_success_on_enter(void* context) { // Clear state of data enter scene scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveData, 0); - popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); + popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58); + popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom); popup_set_context(popup, app); popup_set_callback(popup, lfrfid_popup_timeout_callback); popup_set_timeout(popup, 1500); diff --git a/applications/main/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c index e5bcd4f2d..9d2a38013 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc/scenes/nfc_scene_save_success.c @@ -10,7 +10,8 @@ void nfc_scene_save_success_on_enter(void* context) { // Setup view Popup* popup = nfc->popup; - popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); + popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58); + popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom); popup_set_timeout(popup, 1500); popup_set_context(popup, nfc); popup_set_callback(popup, nfc_scene_save_success_popup_callback); diff --git a/applications/main/subghz/scenes/subghz_scene_save_success.c b/applications/main/subghz/scenes/subghz_scene_save_success.c index 725a504df..9b610b5f5 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_success.c +++ b/applications/main/subghz/scenes/subghz_scene_save_success.c @@ -11,7 +11,8 @@ void subghz_scene_save_success_on_enter(void* context) { // Setup view Popup* popup = subghz->popup; - popup_set_icon(popup, 15, 5, &I_DolphinSaved_113x58); + popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58); + popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom); popup_set_timeout(popup, 1500); popup_set_context(popup, subghz); popup_set_callback(popup, subghz_scene_save_success_popup_callback); diff --git a/assets/icons/iButton/DolphinSaved_92x58.png b/assets/icons/iButton/DolphinSaved_92x58.png new file mode 100644 index 0000000000000000000000000000000000000000..e8704295c6ea182ffdc880ba160182c22531d708 GIT binary patch literal 901 zcmV;01A6?4P){@-kk{WNZ}Qvi3fB-FVegOqTM2h3rnSez_LYQtkumcF zV0%-qBRq<1FP~o)Mxu~GHo%XdNG!B$C*a>PEA&Y zMsKh8McrsAnI}k@H1T3~YQqcnBA*H?Cy-<;<+BtE;(N7@%3YCeSrObO>+*lfb$blOH6t5nabt&j;5h0ngD$gv=99OG_5*t-XFYTrcR zI~ynD%+5cVCr|F%6TD8=cwo^Uluq%VQbozoB2W z*pYr5QoL6}0OU6{^T`~^-pxI%7#=}77u4#1R#>5UVwd)scB(ZfQpe9D#(ko2Q7@$u z=@o!CcU1O_BXRRev*I$IBefx^h&`KPyKn+vv=PWEUUKYceR@=(eVbxMzDav_RL*!D z2ekWL1fJjJxqj>x#UA;(!Q+DySrsx_;M_Z-~5WQm1Ipq%JSC>|zkbg`f|hWN4GT~TPv4jFXBIb#$=PaODZK2y6bV*YP)6Fh bnmE4!Wn>(u#J%>f00000NkvXXu0mjfecYgf literal 0 HcmV?d00001 From 3ec070313e411490b39d6f2fdcd7e53e81cfe7af Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 19 Dec 2023 18:51:54 +0300 Subject: [PATCH 029/110] Removed unnecessary assets DolphinMafia_119x62.png and DolphinSaved_113x58.png --- assets/icons/iButton/DolphinMafia_119x62.png | Bin 1280 -> 0 bytes assets/icons/iButton/DolphinSaved_113x58.png | Bin 1788 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 assets/icons/iButton/DolphinMafia_119x62.png delete mode 100644 assets/icons/iButton/DolphinSaved_113x58.png diff --git a/assets/icons/iButton/DolphinMafia_119x62.png b/assets/icons/iButton/DolphinMafia_119x62.png deleted file mode 100644 index 1bbbec84ad7c1ddc9c58e5bfdbe577a07fed89f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1280 zcmV+b1^@bqP)APj_?zW*z8e~zA_NT6>V$2*g88-oxmD+#wr zA7ivDq4zFwXpGUbeff0!oOYnKS3;$v%{~vwJo*XcVs&~5>b;MLU>YUlN<%G%M#T@o z?+6de6p>?$J_+Ei(SAH=?N5Y}-usxZNff+h6FY5r?c5D6aw$T0L{isj3tk`iVa~a* zTD1@w9g3gu{tlONJ;ZW~wJP`t&F?TN*F$J#5k=X}uGFs#bF~~raP$U%+IB_db5`8(yP3LcPk9^xfs%-Mvp&_ngxYe#3)`2Mbhxjqj2IYqqH( z8IFg~=UN|N|31b@CDv=#;s^ZQQ!Qtok+lRufAEHwZQ%V7a;1bybFSAHXva%V7QvYt z=a-AtT8O$hVl5M}5*)QyRG5sg3+-oZnAZNUL&!g+bD;sguOZAb@n~XqZK#)JEUNEn z&0u?Yof`(OgIl@T#go(r>ll);GL)NP7sIVwoNKwFO1rbA4h{DDsgu~ zMTKOqa-~IAL{!*~V|kKxm2>j%<3~$QIdhLF$OoLblfQXKE$vNDkU^} zQkKJgh98n~Uy7XMvol0!&Rspos4R}Ke^gGD^t_S!n|rpQ+MPHOEyHqza;e-3iS*`P$%4b5wc%6S zA8v%mlw$!&F3w$6irYa$EEl4&q9Jw*t66wBhGyQY{7U(Ag5Z~GSxUqTT4Gm| qhU3k4+UUXAi}V+64(i@1<^BaY>0lxz$?l;50000D#cHj5j`+mRgp4}J~ zF_Y&u){VpA@WN)Pb?lnLz6w_t_UpQ4{A6|+!)W4}7|O`laT;)f4U`^0VI-aibO1M` zr__M}4(Ic9b8I{luMJla6ba)_9oRuySu}?e5ah7pL=s>iJxDZLl>C=f=lGD>pybEN zw20QK0w(jU3>w5_M8pyqNd#u#2L(a_4h2g<0tSa1WU|Gka47lxyb4x!9t-(UzY3G2 zlT*ED{h1B7#s>lFG%?FbqY}sgM{EON5AAD3%Gt5`_#^h@{ZK!)Gnh z2BSi!4jr(^?v#8J!&ntUq1|qW?Gl)x6NMrS!-R-fC>9G?4S_A)!r%^p#pW}}pawRA zHd`4pWr3WGxSmR7lzi6P_hFD$t@Z=4#Ws*EHf=%&ZWW4PL`ag(*!s0?j1K(k#z(bn zvFTPI)BzinN)v2Nj6Q>4Hh-Tsn~0L>dhyN5vs3b!ezm zDh>{jV}sZ*i;cl81Q@h!W^E5(C7;A9R5ZXDijJkIBC{QA}zSOaq9V4c{miU77mEd;2 zuii8-3O>_Ihj$N8fB5&+yIHbx+$g^vS?PZ6qPukQ-mtdqqI`aq7QE8jXb>~%_^#~G zVPrKP>`hxc_UQKLxvkedhU%jqIffKmBhM=rv=lbxU zZFx^?CjH~*R(+0qu6*tw(TMrPi~5E?tW`%qR_?|qLQt4o5xiiAa9=#=wyNmtFEb{= zkw;oD(-uo*GZ!8E77r>Kac4r(va2UYc3i-wx;L%R-H@)``q%tfLr2Kr@A z!zV>`=JA&BzMOMn^@JC7UiF9Jqf4uMxu&cyE|zS|O1xc`t_k1OHCM)U zQJieQn;ciIr{{LQEQR;_ZI0U!Gp=n{PF+?}-A!)wrQCUM;sk>E5#aYK_c#8vQzH(! zNpyYnE!S#uR;ijFZ+Z}3dZbI{rL1U;z}?PVsMz|}e>%_MAo1+&-S*Ai6?1)4a$iWw zc}H?RA1u9j+SrK4AR8{_f$>zT;&8_6Of>X>5JA ze9F Date: Wed, 20 Dec 2023 21:16:20 +0300 Subject: [PATCH 030/110] All common dolphins moved to Dolphin folder --- .../{iButton => Dolphin}/DolphinDone_80x58.png | Bin assets/icons/Dolphin/DolphinMafia_119x62.png | Bin 0 -> 1280 bytes .../{iButton => Dolphin}/DolphinSaved_92x58.png | Bin .../DolphinSuccess_91x55.png | Bin .../{iButton => Dolphin}/DolphinWait_61x59.png | Bin .../WarningDolphinFlip_45x42.png | Bin .../WarningDolphin_45x42.png | Bin 7 files changed, 0 insertions(+), 0 deletions(-) rename assets/icons/{iButton => Dolphin}/DolphinDone_80x58.png (100%) create mode 100644 assets/icons/Dolphin/DolphinMafia_119x62.png rename assets/icons/{iButton => Dolphin}/DolphinSaved_92x58.png (100%) rename assets/icons/{iButton => Dolphin}/DolphinSuccess_91x55.png (100%) rename assets/icons/{iButton => Dolphin}/DolphinWait_61x59.png (100%) rename assets/icons/{Interface => Dolphin}/WarningDolphinFlip_45x42.png (100%) rename assets/icons/{Interface => Dolphin}/WarningDolphin_45x42.png (100%) diff --git a/assets/icons/iButton/DolphinDone_80x58.png b/assets/icons/Dolphin/DolphinDone_80x58.png similarity index 100% rename from assets/icons/iButton/DolphinDone_80x58.png rename to assets/icons/Dolphin/DolphinDone_80x58.png diff --git a/assets/icons/Dolphin/DolphinMafia_119x62.png b/assets/icons/Dolphin/DolphinMafia_119x62.png new file mode 100644 index 0000000000000000000000000000000000000000..1bbbec84ad7c1ddc9c58e5bfdbe577a07fed89f2 GIT binary patch literal 1280 zcmV+b1^@bqP)APj_?zW*z8e~zA_NT6>V$2*g88-oxmD+#wr zA7ivDq4zFwXpGUbeff0!oOYnKS3;$v%{~vwJo*XcVs&~5>b;MLU>YUlN<%G%M#T@o z?+6de6p>?$J_+Ei(SAH=?N5Y}-usxZNff+h6FY5r?c5D6aw$T0L{isj3tk`iVa~a* zTD1@w9g3gu{tlONJ;ZW~wJP`t&F?TN*F$J#5k=X}uGFs#bF~~raP$U%+IB_db5`8(yP3LcPk9^xfs%-Mvp&_ngxYe#3)`2Mbhxjqj2IYqqH( z8IFg~=UN|N|31b@CDv=#;s^ZQQ!Qtok+lRufAEHwZQ%V7a;1bybFSAHXva%V7QvYt z=a-AtT8O$hVl5M}5*)QyRG5sg3+-oZnAZNUL&!g+bD;sguOZAb@n~XqZK#)JEUNEn z&0u?Yof`(OgIl@T#go(r>ll);GL)NP7sIVwoNKwFO1rbA4h{DDsgu~ zMTKOqa-~IAL{!*~V|kKxm2>j%<3~$QIdhLF$OoLblfQXKE$vNDkU^} zQkKJgh98n~Uy7XMvol0!&Rspos4R}Ke^gGD^t_S!n|rpQ+MPHOEyHqza;e-3iS*`P$%4b5wc%6S zA8v%mlw$!&F3w$6irYa$EEl4&q9Jw*t66wBhGyQY{7U(Ag5Z~GSxUqTT4Gm| qhU3k4+UUXAi}V+64(i@1<^BaY>0lxz$?l;50000 Date: Wed, 20 Dec 2023 21:41:43 +0300 Subject: [PATCH 031/110] Moved DolphinReadingSuccess_59x63.png to Dolphin folder --- .../DolphinReadingSuccess_59x63.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename assets/icons/{Infrared => Dolphin}/DolphinReadingSuccess_59x63.png (100%) diff --git a/assets/icons/Infrared/DolphinReadingSuccess_59x63.png b/assets/icons/Dolphin/DolphinReadingSuccess_59x63.png similarity index 100% rename from assets/icons/Infrared/DolphinReadingSuccess_59x63.png rename to assets/icons/Dolphin/DolphinReadingSuccess_59x63.png From 3edbf8f538bf84cd795db0aab1efa7b1eb66ba6a Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 28 Dec 2023 12:09:02 +0300 Subject: [PATCH 032/110] Set proper led color for detect and read scenes --- .../main/nfc/helpers/protocol_support/nfc_protocol_support.c | 2 +- applications/main/nfc/nfc_app.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index fefc56c35..9a5b3c7df 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -162,7 +162,7 @@ static void nfc_protocol_support_scene_read_on_enter(NfcApp* instance) { // Start poller with the appropriate callback nfc_protocol_support[protocol]->scene_read.on_enter(instance); - nfc_blink_detect_start(instance); + nfc_blink_read_start(instance); } static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneManagerEvent event) { diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index ec528ad9c..0cacc882f 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -223,7 +223,7 @@ void nfc_text_store_clear(NfcApp* nfc) { } void nfc_blink_read_start(NfcApp* nfc) { - notification_message(nfc->notifications, &sequence_blink_start_cyan); + notification_message(nfc->notifications, &sequence_blink_start_yellow); } void nfc_blink_emulate_start(NfcApp* nfc) { @@ -231,7 +231,7 @@ void nfc_blink_emulate_start(NfcApp* nfc) { } void nfc_blink_detect_start(NfcApp* nfc) { - notification_message(nfc->notifications, &sequence_blink_start_yellow); + notification_message(nfc->notifications, &sequence_blink_start_cyan); } void nfc_blink_stop(NfcApp* nfc) { From d65dfe1958a01907b6ebfd9e37deb931b5756852 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 28 Dec 2023 14:51:09 +0300 Subject: [PATCH 033/110] Added new notification sequence for semi_success results --- .../notification/notification_messages.c | 18 ++++++++++++++++++ .../notification/notification_messages.h | 1 + targets/f7/api_symbols.csv | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/applications/services/notification/notification_messages.c b/applications/services/notification/notification_messages.c index 28ec327c6..8b7916226 100644 --- a/applications/services/notification/notification_messages.c +++ b/applications/services/notification/notification_messages.c @@ -519,6 +519,24 @@ const NotificationSequence sequence_success = { NULL, }; +const NotificationSequence sequence_semi_success = { + &message_display_backlight_on, + &message_green_255, + &message_vibro_on, + &message_note_c4, + &message_delay_50, + &message_note_e4, + &message_delay_50, + &message_note_g4, + &message_delay_50, + &message_sound_off, + &message_delay_50, + &message_note_c5, + &message_delay_50, + &message_sound_off, + NULL, +}; + const NotificationSequence sequence_error = { &message_display_backlight_on, &message_red_255, diff --git a/applications/services/notification/notification_messages.h b/applications/services/notification/notification_messages.h index d87cf74f4..873bb37a8 100644 --- a/applications/services/notification/notification_messages.h +++ b/applications/services/notification/notification_messages.h @@ -138,6 +138,7 @@ extern const NotificationSequence sequence_blink_stop; extern const NotificationSequence sequence_single_vibro; extern const NotificationSequence sequence_double_vibro; extern const NotificationSequence sequence_success; +extern const NotificationSequence sequence_semi_success; extern const NotificationSequence sequence_error; extern const NotificationSequence sequence_audiovisual_alert; diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 353d511ec..c45ef742f 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,50.0,, +Version,+,50.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -3587,6 +3587,7 @@ Variable,+,sequence_reset_red,const NotificationSequence, Variable,+,sequence_reset_rgb,const NotificationSequence, Variable,+,sequence_reset_sound,const NotificationSequence, Variable,+,sequence_reset_vibro,const NotificationSequence, +Variable,+,sequence_semi_success,const NotificationSequence, Variable,+,sequence_set_blue_255,const NotificationSequence, Variable,+,sequence_set_green_255,const NotificationSequence, Variable,+,sequence_set_only_blue_255,const NotificationSequence, From 305d5bcc83b8c2864c1c3d877896029119e088b1 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 28 Dec 2023 14:52:18 +0300 Subject: [PATCH 034/110] Use new sequence for semi_success nfc reads --- .../main/nfc/helpers/protocol_support/nfc_protocol_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 9a5b3c7df..9130a6f13 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -182,7 +182,7 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana bool card_read = nfc_supported_cards_read( instance->nfc_supported_cards, instance->nfc_device, instance->nfc); if(card_read) { - notification_message(instance->notifications, &sequence_success); + notification_message(instance->notifications, &sequence_semi_success); scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; From cf4b537c379d6188876be73b340c782f4a4f4966 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 28 Dec 2023 14:54:57 +0300 Subject: [PATCH 035/110] Different events are now throwed depending on read result --- .../helpers/protocol_support/mf_ultralight/mf_ultralight.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 4124bd903..70ebf60ff 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -52,7 +52,12 @@ static NfcCommand if(mf_ultralight_event->type == MfUltralightPollerEventTypeReadSuccess) { nfc_device_set_data( instance->nfc_device, NfcProtocolMfUltralight, nfc_poller_get_data(instance->poller)); - view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); + + const MfUltralightData* data = + nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight); + uint32_t event = (data->pages_read == data->pages_total) ? NfcCustomEventPollerSuccess : + NfcCustomEventPollerIncomplete; + view_dispatcher_send_custom_event(instance->view_dispatcher, event); return NfcCommandStop; } else if(mf_ultralight_event->type == MfUltralightPollerEventTypeAuthRequest) { view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected); From bf78ace9e254e508bfc289b9b84aae599c385a00 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 28 Dec 2023 14:55:47 +0300 Subject: [PATCH 036/110] Added handling of incomplete event for ultralight cards --- .../helpers/protocol_support/mf_ultralight/mf_ultralight.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 70ebf60ff..4a8d4d744 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -137,6 +137,10 @@ bool nfc_scene_read_on_event_mf_ultralight(NfcApp* instance, uint32_t event) { scene_manager_set_scene_state( instance->scene_manager, NfcSceneRead, NfcSceneMfUltralightReadMenuStateCardFound); nfc_scene_read_setup_view(instance); + } else if((event == NfcCustomEventPollerIncomplete)) { + notification_message(instance->notifications, &sequence_semi_success); + scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); } return true; } From 4b363472ddb1b2816a7d6a794ca31afe80614bd4 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 28 Dec 2023 15:19:48 +0300 Subject: [PATCH 037/110] Replaced image for iButton scene --- .../ibutton/scenes/ibutton_scene_write_success.c | 2 +- .../iButton/iButtonDolphinVerySuccess_108x52.png | Bin 2157 -> 0 bytes .../iButton/iButtonDolphinVerySuccess_92x55.png | Bin 0 -> 967 bytes 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 assets/icons/iButton/iButtonDolphinVerySuccess_108x52.png create mode 100644 assets/icons/iButton/iButtonDolphinVerySuccess_92x55.png diff --git a/applications/main/ibutton/scenes/ibutton_scene_write_success.c b/applications/main/ibutton/scenes/ibutton_scene_write_success.c index 17cd53d08..b36bccfbc 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_write_success.c +++ b/applications/main/ibutton/scenes/ibutton_scene_write_success.c @@ -10,7 +10,7 @@ void ibutton_scene_write_success_on_enter(void* context) { iButton* ibutton = context; Popup* popup = ibutton->popup; - popup_set_icon(popup, 0, 12, &I_iButtonDolphinVerySuccess_108x52); + popup_set_icon(popup, 0, 9, &I_iButtonDolphinVerySuccess_92x55); popup_set_text(popup, "Successfully written!", 40, 12, AlignLeft, AlignBottom); popup_set_callback(popup, ibutton_scene_write_success_popup_callback); diff --git a/assets/icons/iButton/iButtonDolphinVerySuccess_108x52.png b/assets/icons/iButton/iButtonDolphinVerySuccess_108x52.png deleted file mode 100644 index 2b4bec7c6f14f53e7362da75f95b83bf387eee54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2157 zcmbVO2~ZPP7>*~02PorFsdimdMA+fKow8|q?(QRKr!r*R@tj{x`6Nwm6rph(oMKb4%yr|RP{ zg0_fp1D#2V?H0xj7ln_vGdPh=@<1k;MOjtg(}RaWfHJ7SsWLsHXEdaVigvJMk|REu zaAXro12}#h5N^i=0t?CGfZbxYa+qBOw(?@a+`SBgKr4jLR)K1_Kp<700BC5I1mt1_ zA`k=x6iTr~E|toWFaSkR1V&`A1cfAW43T0I1<-zhf;84(#1gep?XrX~6=>pl27_Un z%_g>u7Sn7NEKw?zFoMD;3JC~^%eV5l9kOyk9SmBMBUp;zDcTCS8SzXymsf#;rfnuz z7!R$LYj>02FxZYWutbcwO=<-i2oH|QWzDU^4FpV@NegM^IRPv2Uu!HmLMbZ1c^Z%iZLddr#Tb-4|aIAJ=QRoh9z;HW|L{! z+!3gR4i*5Fh*4nVRLW|gZCr?3O8Ws)i}R!k6rv`95LCF6Q4~XDm`oljK`;bqgX)Dm zFyK7?-@vqiGUk5}Y9KHp&0285OOyrAB4Ngw)hbP|$6~A;k6Q^cMymn^RmBu#z~oX= zAyX=h5GuSNqe6;6nNlJXl8sgv38P$rAcVBzyp|?%-4X0KZ}^|*C$W@JLAd$jc{~xq zG_;v!^|V3o@@NqFb3I0*NnmLsWfnHLMBM}+CQ>7pDCKep6-(TS-kNY&G{p%~&2KNA zBr>OcW~PAF9K&$JT?Q(UaL1oCfbGlFN4v0%)@C9F(tpW|HW)`6c^l4>>MX(CAIv*g zP#$&{Y?~eM-%V`Y`%7_mz=e+Co_bo9@Zo88q*dr}tkBAQ5}G1KqRww)wCZGg`K{GA zoW}w0;vDp8%bD|$0VhRZaP^aU-_`NZ!(iWfs5*t&z8tl<RcBM(Lo_&0F%-q_ojos_KXD@w|bUY$` z@QA0blA+dA6CC92eP`Xy9k&B+7hX;`pS<>9#gIE(Swzdl8>=K~&gP(t_vgm1`L!;8 z`^clyDwm$UhGqwx`u;g}Uw$_L==$Qd1JuOH4+&d9*ORIU%T@ z*7ixc6E>y4yb*XcZeHUkzZ`yBL~KUNLf@5?>cW;jFV8r?O6d+l_u>xJ28WJI^14{G zIlXJ*L!ZV0nydbX!MZ(922~t>VLDtDH+kjVqnRaP>g(G6Iay!^Pc3_PJ?+Kx(yxI<^BY^Q)!X-B-}(oy5N+XFBB^Sf z?vbpf%vIRpd+-af*PHbPft%M(tK2P$U2vT650vE%Yr0hNHl(P`VRLppvTRXb*|emG zvuEu8@_f_8mL2=@!urCeyHep%6}v;S`zZz&d*AsX>QmS2)wT9l(;MgHFIzgjsv_tF zzBjPum)d=fnViot)zA~qi)SfqibKE6xBu?HwuaTsysTWeNb7iayFpw4bvfd86yBh8lfri^n;OsV zF?gXW`~+pc38s>QmAzYCH&41qI8-!z$Xg%w1gJ}UOnNEf3a2J$_gk_HY}4dw_Xtta zq9tNMb7S)q6+WYEOa`a&8%g6}c@}dG@83O%sU5-FdxCe&B;lOz_9#)>ew|hJO1Glr zvA(IS!oBXqTOv+ZIiB3nef|!X@GN%%kDX4khFWW*n!hAEwrNuCB&xwtN{J$$i{l+P zB{)nnejX{;7vYk!Bi%$~)3m(mUK@(JkVGemvgaoi&M7<6!p)LBQcvMEo@bEm)%KV0 zM3aQiC>-9axd?dP5_^TWfeUyw;D317k=N$SIpGN0|y=g;AnCrI90=%gc?4-MoUYPt*b>8ukCux?9kU z_|kEh7hel)F+BHBxMqW*kmYf+a#JOSYn)o_FNNcp-2=hTU6@sL1lbaBQzhf=Pt z`m6me*OEDzo|+u>hKDFTgB(gpBj-7ADz)4*nv0B87S-^~9$;0hr-WGIj>KM8!~6X! zN(FV?JK>RJmx2_&%AG_ny|qc4DLv8GJ`}#no%9--t$1&p&xES*C4-pQij`J~Gvmon zcPYpgT349SlYtiz-g|Gr5eh#End&aZP{aFi`1uFF&3zEAttj8Fcr3IGd Date: Thu, 28 Dec 2023 15:24:26 +0300 Subject: [PATCH 038/110] Updated API for f18 --- targets/f18/api_symbols.csv | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 8a5e44c97..aaab39f40 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,50.0,, +Version,v,50.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2796,6 +2796,7 @@ Variable,+,sequence_reset_red,const NotificationSequence, Variable,+,sequence_reset_rgb,const NotificationSequence, Variable,+,sequence_reset_sound,const NotificationSequence, Variable,+,sequence_reset_vibro,const NotificationSequence, +Variable,+,sequence_semi_success,const NotificationSequence, Variable,+,sequence_set_blue_255,const NotificationSequence, Variable,+,sequence_set_green_255,const NotificationSequence, Variable,+,sequence_set_only_blue_255,const NotificationSequence, From e2a7d5f3f4ac37c8b366362df42be46e1f2619c9 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 29 Dec 2023 12:06:43 +0300 Subject: [PATCH 039/110] Fixed issue with unlock retry sequence --- applications/main/nfc/scenes/nfc_scene_retry_confirm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c index 03b0fb293..99acbb0b8 100644 --- a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c @@ -28,7 +28,11 @@ bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { if(event.event == DialogExResultRight) { consumed = scene_manager_previous_scene(nfc->scene_manager); } else if(event.event == DialogExResultLeft) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneDetect)) { + if(scene_manager_has_previous_scene( + nfc->scene_manager, NfcSceneMfUltralightUnlockWarn)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneDetect)) { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneDetect); } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneRead)) { From 82ecc8e73f6f25b99bf8c06dee4ebb892e57de69 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 29 Dec 2023 12:09:33 +0300 Subject: [PATCH 040/110] Fix after review --- .../main/nfc/helpers/protocol_support/nfc_protocol_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 9130a6f13..9a5b3c7df 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -182,7 +182,7 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana bool card_read = nfc_supported_cards_read( instance->nfc_supported_cards, instance->nfc_device, instance->nfc); if(card_read) { - notification_message(instance->notifications, &sequence_semi_success); + notification_message(instance->notifications, &sequence_success); scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; From 0a44c75b20b944cabf179f86b6e12a6422c8528a Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 29 Dec 2023 13:09:46 +0300 Subject: [PATCH 041/110] Success notification replaced to semi success in case of incomplete mf classic reading --- applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index b6ba1c119..3ed2696a3 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -231,7 +231,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent } consumed = true; } else if(state == DictAttackStateSystemDictInProgress) { - notification_message(instance->notifications, &sequence_success); + notification_message(instance->notifications, &sequence_semi_success); scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; From c9ffe4ab4d260f20a33437439401ac4d5cfe4e23 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 29 Dec 2023 16:37:30 +0300 Subject: [PATCH 042/110] New text for read scene --- .../main/nfc/helpers/protocol_support/nfc_protocol_support.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 9a5b3c7df..ad7f5a0d1 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -146,8 +146,7 @@ static void nfc_protocol_support_scene_more_info_on_exit(NfcApp* instance) { // SceneRead static void nfc_protocol_support_scene_read_on_enter(NfcApp* instance) { - popup_set_header( - instance->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); + popup_set_header(instance->popup, "Don't move", 85, 27, AlignCenter, AlignTop); popup_set_icon(instance->popup, 12, 23, &A_Loading_24); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); From 18fbe364f2f1f11f67102dd67b9f5281752ae9df Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 29 Dec 2023 16:38:00 +0300 Subject: [PATCH 043/110] New read result sound notification logic for mf classic cards --- .../scenes/nfc_scene_mf_classic_dict_attack.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 3ed2696a3..328e39132 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -175,6 +175,16 @@ void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance); } +static void nfc_scene_mf_classic_dict_attack_notify_read(NfcApp* instance) { + const MfClassicData* mfc_data = nfc_poller_get_data(instance->poller); + bool is_card_fully_read = mf_classic_is_card_read(mfc_data); + if(is_card_fully_read) { + notification_message(instance->notifications, &sequence_success); + } else { + notification_message(instance->notifications, &sequence_semi_success); + } +} + bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { NfcApp* instance = context; bool consumed = false; @@ -196,7 +206,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance); consumed = true; } else { - notification_message(instance->notifications, &sequence_success); + nfc_scene_mf_classic_dict_attack_notify_read(instance); scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; @@ -225,13 +235,13 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic); nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance); } else { - notification_message(instance->notifications, &sequence_success); + nfc_scene_mf_classic_dict_attack_notify_read(instance); scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); } consumed = true; } else if(state == DictAttackStateSystemDictInProgress) { - notification_message(instance->notifications, &sequence_semi_success); + nfc_scene_mf_classic_dict_attack_notify_read(instance); scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; From d0c466ccc0c1185e1d6f69058cfc0a7f8951afe3 Mon Sep 17 00:00:00 2001 From: Methodius Date: Thu, 11 Jan 2024 00:48:55 +0900 Subject: [PATCH 044/110] EMV protocol added --- lib/nfc/protocols/emv/emv.c | 111 ++++++ lib/nfc/protocols/emv/emv.h | 100 +++++ lib/nfc/protocols/emv/emv_poller.c | 206 ++++++++++ lib/nfc/protocols/emv/emv_poller.h | 51 +++ lib/nfc/protocols/emv/emv_poller_defs.h | 5 + lib/nfc/protocols/emv/emv_poller_i.c | 477 ++++++++++++++++++++++++ lib/nfc/protocols/emv/emv_poller_i.h | 52 +++ lib/nfc/protocols/nfc_poller_defs.c | 2 + lib/nfc/protocols/nfc_protocol.c | 31 +- lib/nfc/protocols/nfc_protocol.h | 25 +- 10 files changed, 1037 insertions(+), 23 deletions(-) create mode 100644 lib/nfc/protocols/emv/emv.c create mode 100644 lib/nfc/protocols/emv/emv.h create mode 100644 lib/nfc/protocols/emv/emv_poller.c create mode 100644 lib/nfc/protocols/emv/emv_poller.h create mode 100644 lib/nfc/protocols/emv/emv_poller_defs.h create mode 100644 lib/nfc/protocols/emv/emv_poller_i.c create mode 100644 lib/nfc/protocols/emv/emv_poller_i.h diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c new file mode 100644 index 000000000..2de6fb132 --- /dev/null +++ b/lib/nfc/protocols/emv/emv.c @@ -0,0 +1,111 @@ +//#include "emv_i.h" + +#include +#include "protocols/emv/emv.h" +#include +#include + +#define EMV_PROTOCOL_NAME "EMV" + +const NfcDeviceBase nfc_device_emv = { + .protocol_name = EMV_PROTOCOL_NAME, + .alloc = (NfcDeviceAlloc)emv_alloc, + .free = (NfcDeviceFree)emv_free, + .reset = (NfcDeviceReset)emv_reset, + .copy = (NfcDeviceCopy)emv_copy, + .verify = (NfcDeviceVerify)emv_verify, + .load = (NfcDeviceLoad)emv_load, + .save = (NfcDeviceSave)emv_save, + .is_equal = (NfcDeviceEqual)emv_is_equal, + .get_name = (NfcDeviceGetName)emv_get_device_name, + .get_uid = (NfcDeviceGetUid)emv_get_uid, + .set_uid = (NfcDeviceSetUid)emv_set_uid, + .get_base_data = (NfcDeviceGetBaseData)emv_get_base_data, +}; + +EmvData* emv_alloc() { + EmvData* data = malloc(sizeof(EmvData)); + data->iso14443_4a_data = iso14443_4a_alloc(); + + return data; +} + +void emv_free(EmvData* data) { + furi_assert(data); + + emv_reset(data); + iso14443_4a_free(data->iso14443_4a_data); + free(data); +} + +void emv_reset(EmvData* data) { + furi_assert(data); + + iso14443_4a_reset(data->iso14443_4a_data); + + memset(&data->emv_application, 0, sizeof(EmvApplication)); +} + +void emv_copy(EmvData* destination, const EmvData* source) { + furi_assert(destination); + furi_assert(source); + + emv_reset(destination); + + iso14443_4a_copy(destination->iso14443_4a_data, source->iso14443_4a_data); + destination->emv_application = source->emv_application; +} + +bool emv_verify(EmvData* data, const FuriString* device_type) { + UNUSED(data); + return furi_string_equal_str(device_type, EMV_PROTOCOL_NAME); +} + +bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { + furi_assert(data); + UNUSED(data); + UNUSED(ff); + UNUSED(version); + + return false; +} + +bool emv_save(const EmvData* data, FlipperFormat* ff) { + furi_assert(data); + UNUSED(data); + UNUSED(ff); + + return false; +} + +bool emv_is_equal(const EmvData* data, const EmvData* other) { + furi_assert(data); + furi_assert(other); + + return iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data) && + memcmp(&data->emv_application, &other->emv_application, sizeof(EmvApplication)) == 0; +} + +const char* emv_get_device_name(const EmvData* data, NfcDeviceNameType name_type) { + UNUSED(data); + UNUSED(name_type); + return EMV_PROTOCOL_NAME; +} + +const uint8_t* emv_get_uid(const EmvData* data, size_t* uid_len) { + furi_assert(data); + + return iso14443_4a_get_uid(data->iso14443_4a_data, uid_len); +} + +bool emv_set_uid(EmvData* data, const uint8_t* uid, size_t uid_len) { + furi_assert(data); + + return iso14443_4a_set_uid(data->iso14443_4a_data, uid, uid_len); +} + +Iso14443_4aData* emv_get_base_data(const EmvData* data) { + furi_assert(data); + + return data->iso14443_4a_data; +} \ No newline at end of file diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h new file mode 100644 index 000000000..feb390c7d --- /dev/null +++ b/lib/nfc/protocols/emv/emv.h @@ -0,0 +1,100 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_APDU_LEN 255 + +#define EMV_TAG_APP_TEMPLATE 0x61 +#define EMV_TAG_AID 0x4F +#define EMV_TAG_PRIORITY 0x87 +#define EMV_TAG_PDOL 0x9F38 +#define EMV_TAG_CARD_NAME 0x50 +#define EMV_TAG_FCI 0xBF0C +#define EMV_TAG_LOG_CTRL 0x9F4D +#define EMV_TAG_TRACK_1_EQUIV 0x56 +#define EMV_TAG_TRACK_2_EQUIV 0x57 +#define EMV_TAG_PAN 0x5A +#define EMV_TAG_AFL 0x94 +#define EMV_TAG_EXP_DATE 0x5F24 +#define EMV_TAG_COUNTRY_CODE 0x5F28 +#define EMV_TAG_CURRENCY_CODE 0x9F42 +#define EMV_TAG_CARDHOLDER_NAME 0x5F20 + +typedef struct { + uint16_t tag; + uint8_t data[]; +} PDOLValue; + +typedef struct { + uint8_t size; + uint8_t data[MAX_APDU_LEN]; +} APDU; + +typedef struct { + uint8_t priority; + uint8_t aid[16]; + uint8_t aid_len; + bool app_started; + char name[32]; + bool name_found; + uint8_t card_number[10]; + uint8_t card_number_len; + uint8_t exp_month; + uint8_t exp_year; + uint16_t country_code; + uint16_t currency_code; + APDU pdol; + APDU afl; +} EmvApplication; + +typedef enum { + EmvErrorNone = 0, + EmvErrorNotPresent, + EmvErrorProtocol, + EmvErrorTimeout, +} EmvError; + +typedef struct { + Iso14443_4aData* iso14443_4a_data; + EmvApplication emv_application; +} EmvData; + +extern const NfcDeviceBase nfc_device_emv; + +// Virtual methods + +EmvData* emv_alloc(); + +void emv_free(EmvData* data); + +void emv_reset(EmvData* data); + +void emv_copy(EmvData* data, const EmvData* other); + +bool emv_verify(EmvData* data, const FuriString* device_type); + +bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version); + +bool emv_save(const EmvData* data, FlipperFormat* ff); + +bool emv_is_equal(const EmvData* data, const EmvData* other); + +const char* emv_get_device_name(const EmvData* data, NfcDeviceNameType name_type); + +const uint8_t* emv_get_uid(const EmvData* data, size_t* uid_len); + +bool emv_set_uid(EmvData* data, const uint8_t* uid, size_t uid_len); + +Iso14443_4aData* emv_get_base_data(const EmvData* data); + +// Getters and tests + +const EmvApplication* emv_get_application(const EmvData* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c new file mode 100644 index 000000000..46f02b363 --- /dev/null +++ b/lib/nfc/protocols/emv/emv_poller.c @@ -0,0 +1,206 @@ +#include "emv_poller_i.h" + +#include + +#include + +#define TAG "EMVPoller" + +// SKOLKO????????????????????????????????????????????????????????????????? +#define EMV_BUF_SIZE (512U) +#define EMV_RESULT_BUF_SIZE (512U) + +typedef NfcCommand (*EmvPollerReadHandler)(EmvPoller* instance); + +const EmvData* emv_poller_get_data(EmvPoller* instance) { + furi_assert(instance); + + return instance->data; +} + +static EmvPoller* emv_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller) { + EmvPoller* instance = malloc(sizeof(EmvPoller)); + instance->iso14443_4a_poller = iso14443_4a_poller; + instance->data = emv_alloc(); + instance->tx_buffer = bit_buffer_alloc(EMV_BUF_SIZE); + instance->rx_buffer = bit_buffer_alloc(EMV_BUF_SIZE); + instance->input_buffer = bit_buffer_alloc(EMV_BUF_SIZE); + instance->result_buffer = bit_buffer_alloc(EMV_RESULT_BUF_SIZE); + + instance->emv_event.data = &instance->emv_event_data; + + instance->general_event.protocol = NfcProtocolEmv; + instance->general_event.event_data = &instance->emv_event; + instance->general_event.instance = instance; + + return instance; +} + +static void emv_poller_free(EmvPoller* instance) { + furi_assert(instance); + + emv_free(instance->data); + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + bit_buffer_free(instance->input_buffer); + bit_buffer_free(instance->result_buffer); + free(instance); +} + +static NfcCommand emv_poller_handler_idle(EmvPoller* instance) { + bit_buffer_reset(instance->input_buffer); + bit_buffer_reset(instance->result_buffer); + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + iso14443_4a_copy( + instance->data->iso14443_4a_data, + iso14443_4a_poller_get_data(instance->iso14443_4a_poller)); + + instance->state = EmvPollerStateSelectPPSE; + return NfcCommandContinue; +} + +static NfcCommand emv_poller_handler_select_ppse(EmvPoller* instance) { + instance->error = emv_poller_select_ppse(instance); + if(instance->error == EmvErrorNone) { + FURI_LOG_D(TAG, "Select PPSE success"); + instance->state = EmvPollerStateSelectApplication; + } else { + FURI_LOG_E(TAG, "Failed to select PPSE"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->state = EmvPollerStateReadFailed; + } + + return NfcCommandContinue; +} + +static NfcCommand emv_poller_handler_select_application(EmvPoller* instance) { + instance->error = emv_poller_select_ppse(instance); + if(instance->error == EmvErrorNone) { + FURI_LOG_D(TAG, "Select application success"); + instance->state = EmvPollerStateGetProcessingOptions; + } else { + FURI_LOG_E(TAG, "Failed to select application"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->state = EmvPollerStateReadFailed; + } + + return NfcCommandContinue; +} + +static NfcCommand emv_poller_handler_get_processing_options(EmvPoller* instance) { + instance->error = emv_poller_get_processing_options(instance); + + if(instance->error == EmvErrorNone) { + FURI_LOG_D(TAG, "Get processing options success"); + instance->state = EmvPollerStateReadSuccess; + } else { + FURI_LOG_E(TAG, "Failed to get processing options"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->state = EmvPollerStateReadFiles; + } + + return NfcCommandContinue; +} + +static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) { + instance->error = emv_poller_read_files(instance); + + if(instance->error == EmvErrorNone) { + FURI_LOG_D(TAG, "Read files success"); + instance->state = EmvPollerStateReadSuccess; + } else { + FURI_LOG_E(TAG, "Failed to read files"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->state = EmvPollerStateReadFailed; + } + + return NfcCommandContinue; +} + +static NfcCommand emv_poller_handler_read_fail(EmvPoller* instance) { + FURI_LOG_D(TAG, "Read failed"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->emv_event.data->error = instance->error; + NfcCommand command = instance->callback(instance->general_event, instance->context); + instance->state = EmvPollerStateIdle; + return command; +} + +static NfcCommand emv_poller_handler_read_success(EmvPoller* instance) { + FURI_LOG_D(TAG, "Read success."); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->emv_event.type = EmvPollerEventTypeReadSuccess; + NfcCommand command = instance->callback(instance->general_event, instance->context); + return command; +} + +static const EmvPollerReadHandler emv_poller_read_handler[EmvPollerStateNum] = { + [EmvPollerStateIdle] = emv_poller_handler_idle, + [EmvPollerStateSelectPPSE] = emv_poller_handler_select_ppse, + [EmvPollerStateSelectApplication] = emv_poller_handler_select_application, + [EmvPollerStateGetProcessingOptions] = emv_poller_handler_get_processing_options, + [EmvPollerStateReadFiles] = emv_poller_handler_read_files, + [EmvPollerStateReadFailed] = emv_poller_handler_read_fail, + [EmvPollerStateReadSuccess] = emv_poller_handler_read_success, +}; + +static void + emv_poller_set_callback(EmvPoller* instance, NfcGenericCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +static NfcCommand emv_poller_run(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolIso14443_4a); + + EmvPoller* instance = context; + furi_assert(instance); + furi_assert(instance->callback); + + const Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data; + furi_assert(iso14443_4a_event); + + NfcCommand command = NfcCommandContinue; + + if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) { + command = emv_poller_read_handler[instance->state](instance); + } else if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeError) { + instance->emv_event.type = EmvPollerEventTypeReadFailed; + command = instance->callback(instance->general_event, instance->context); + } + + return command; +} + +static bool emv_poller_detect(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolIso14443_4a); + + EmvPoller* instance = context; + furi_assert(instance); + + const Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data; + furi_assert(iso14443_4a_event); + + bool protocol_detected = false; + + if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) { + const EmvError error = emv_poller_select_ppse(instance); + protocol_detected = (error == EmvErrorNone); + } + + return protocol_detected; +} + +const NfcPollerBase emv_poller = { + .alloc = (NfcPollerAlloc)emv_poller_alloc, + .free = (NfcPollerFree)emv_poller_free, + .set_callback = (NfcPollerSetCallback)emv_poller_set_callback, + .run = (NfcPollerRun)emv_poller_run, + .detect = (NfcPollerDetect)emv_poller_detect, + .get_data = (NfcPollerGetData)emv_poller_get_data, +}; \ No newline at end of file diff --git a/lib/nfc/protocols/emv/emv_poller.h b/lib/nfc/protocols/emv/emv_poller.h new file mode 100644 index 000000000..f86186fe2 --- /dev/null +++ b/lib/nfc/protocols/emv/emv_poller.h @@ -0,0 +1,51 @@ +#pragma once + +#include "emv.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief EmvPoller opaque type definition. + */ +typedef struct EmvPoller EmvPoller; + +/** + * @brief Enumeration of possible Emv poller event types. + */ +typedef enum { + EmvPollerEventTypeReadSuccess, /**< Card was read successfully. */ + EmvPollerEventTypeReadFailed, /**< Poller failed to read card. */ +} EmvPollerEventType; + +/** + * @brief Emv poller event data. + */ +typedef union { + EmvError error; /**< Error code indicating card reading fail reason. */ +} EmvPollerEventData; + +/** + * @brief Emv poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ +typedef struct { + EmvPollerEventType type; /**< Type of emmitted event. */ + EmvPollerEventData* data; /**< Pointer to event specific data. */ +} EmvPollerEvent; + +EmvError emv_poller_select_ppse(EmvPoller* instance); + +EmvError emv_poller_select_application(EmvPoller* instance); + +EmvError emv_poller_get_processing_options(EmvPoller* instance); + +EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t record_num); + +EmvError emv_poller_read_files(EmvPoller* instance); + +EmvError emv_poller_read(EmvPoller* instance); \ No newline at end of file diff --git a/lib/nfc/protocols/emv/emv_poller_defs.h b/lib/nfc/protocols/emv/emv_poller_defs.h new file mode 100644 index 000000000..001910112 --- /dev/null +++ b/lib/nfc/protocols/emv/emv_poller_defs.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +extern const NfcPollerBase emv_poller; \ No newline at end of file diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c new file mode 100644 index 000000000..22c862661 --- /dev/null +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -0,0 +1,477 @@ +#include "emv_poller_i.h" +#include "protocols/emv/emv.h" + +#define TAG "EMVPoller" + +const PDOLValue pdol_term_info = {0x9F59, {0xC8, 0x80, 0x00}}; // Terminal transaction information +const PDOLValue pdol_term_type = {0x9F5A, {0x00}}; // Terminal transaction type +const PDOLValue pdol_merchant_type = {0x9F58, {0x01}}; // Merchant type indicator +const PDOLValue pdol_term_trans_qualifies = { + 0x9F66, + {0x79, 0x00, 0x40, 0x80}}; // Terminal transaction qualifiers +const PDOLValue pdol_addtnl_term_qualifies = { + 0x9F40, + {0x79, 0x00, 0x40, 0x80}}; // Terminal transaction qualifiers +const PDOLValue pdol_amount_authorise = { + 0x9F02, + {0x00, 0x00, 0x00, 0x10, 0x00, 0x00}}; // Amount, authorised +const PDOLValue pdol_amount = {0x9F03, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // Amount +const PDOLValue pdol_country_code = {0x9F1A, {0x01, 0x24}}; // Terminal country code +const PDOLValue pdol_currency_code = {0x5F2A, {0x01, 0x24}}; // Transaction currency code +const PDOLValue pdol_term_verification = { + 0x95, + {0x00, 0x00, 0x00, 0x00, 0x00}}; // Terminal verification results +const PDOLValue pdol_transaction_date = {0x9A, {0x19, 0x01, 0x01}}; // Transaction date +const PDOLValue pdol_transaction_type = {0x9C, {0x00}}; // Transaction type +const PDOLValue pdol_transaction_cert = {0x98, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; // Transaction cert +const PDOLValue pdol_unpredict_number = {0x9F37, {0x82, 0x3D, 0xDE, 0x7A}}; // Unpredictable number + +const PDOLValue* const pdol_values[] = { + &pdol_term_info, + &pdol_term_type, + &pdol_merchant_type, + &pdol_term_trans_qualifies, + &pdol_addtnl_term_qualifies, + &pdol_amount_authorise, + &pdol_amount, + &pdol_country_code, + &pdol_currency_code, + &pdol_term_verification, + &pdol_transaction_date, + &pdol_transaction_type, + &pdol_transaction_cert, + &pdol_unpredict_number, +}; + +EmvError emv_process_error(Iso14443_4aError error) { + switch(error) { + case Iso14443_4aErrorNone: + return EmvErrorNone; + case Iso14443_4aErrorNotPresent: + return EmvErrorNotPresent; + case Iso14443_4aErrorTimeout: + return EmvErrorTimeout; + default: + return EmvErrorProtocol; + } +} + +static void emv_trace(EmvPoller* instance, const char* message) { + if(furi_log_get_level() == FuriLogLevelTrace) { + FURI_LOG_T(TAG, "%s", message); + + printf("TX: "); + size_t size = bit_buffer_get_size_bytes(instance->tx_buffer); + for(size_t i = 0; i < size; i++) { + printf("%02X ", bit_buffer_get_byte(instance->tx_buffer, i)); + } + + printf("\r\nRX: "); + size = bit_buffer_get_size_bytes(instance->rx_buffer); + for(size_t i = 0; i < size; i++) { + printf("%02X ", bit_buffer_get_byte(instance->rx_buffer, i)); + } + printf("\r\n"); + } +} + +static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) { + bool tag_found; + for(uint16_t i = 0; i < src->size; i++) { + tag_found = false; + for(uint8_t j = 0; j < sizeof(pdol_values) / sizeof(PDOLValue*); j++) { + if(src->data[i] == pdol_values[j]->tag) { + // Found tag with 1 byte length + uint8_t len = src->data[++i]; + memcpy(dest->data + dest->size, pdol_values[j]->data, len); + dest->size += len; + tag_found = true; + break; + } else if(((src->data[i] << 8) | src->data[i + 1]) == pdol_values[j]->tag) { + // Found tag with 2 byte length + i += 2; + uint8_t len = src->data[i]; + memcpy(dest->data + dest->size, pdol_values[j]->data, len); + dest->size += len; + tag_found = true; + break; + } + } + if(!tag_found) { + // Unknown tag, fill zeros + i += 2; + uint8_t len = src->data[i]; + memset(dest->data + dest->size, 0, len); + dest->size += len; + } + } + return dest->size; +} + +static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplication* app) { + uint16_t i = 0; + uint16_t tag = 0, first_byte = 0; + uint16_t tlen = 0; + bool success = false; + + while(i < len) { + first_byte = buff[i]; + if((first_byte & 31) == 31) { // 2-byte tag + tag = buff[i] << 8 | buff[i + 1]; + i++; + FURI_LOG_T(TAG, " 2-byte TLV EMV tag: %x", tag); + } else { + tag = buff[i]; + FURI_LOG_T(TAG, " 1-byte TLV EMV tag: %x", tag); + } + i++; + tlen = buff[i]; + if((tlen & 128) == 128) { // long length value + i++; + tlen = buff[i]; + FURI_LOG_T(TAG, " 2-byte TLV length: %d", tlen); + } else { + FURI_LOG_T(TAG, " 1-byte TLV length: %d", tlen); + } + i++; + if((first_byte & 32) == 32) { // "Constructed" -- contains more TLV data to parse + FURI_LOG_T(TAG, "Constructed TLV %x", tag); + if(!emv_decode_response(&buff[i], tlen, app)) { + FURI_LOG_T(TAG, "Failed to decode response for %x", tag); + // return false; + } else { + success = true; + } + } else { + switch(tag) { + case EMV_TAG_AID: + app->aid_len = tlen; + memcpy(app->aid, &buff[i], tlen); + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_AID %x", tag); + break; + case EMV_TAG_PRIORITY: + memcpy(&app->priority, &buff[i], tlen); + success = true; + break; + case EMV_TAG_CARD_NAME: + memcpy(app->name, &buff[i], tlen); + app->name[tlen] = '\0'; + app->name_found = true; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_CARD_NAME %x : %s", tag, app->name); + break; + case EMV_TAG_PDOL: + memcpy(app->pdol.data, &buff[i], tlen); + app->pdol.size = tlen; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_PDOL %x (len=%d)", tag, tlen); + break; + case EMV_TAG_AFL: + memcpy(app->afl.data, &buff[i], tlen); + app->afl.size = tlen; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_AFL %x (len=%d)", tag, tlen); + break; + case EMV_TAG_TRACK_1_EQUIV: { + char track_1_equiv[80]; + memcpy(track_1_equiv, &buff[i], tlen); + track_1_equiv[tlen] = '\0'; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_1_EQUIV %x : %s", tag, track_1_equiv); + break; + } + case EMV_TAG_TRACK_2_EQUIV: { + // 0xD0 delimits PAN from expiry (YYMM) + for(int x = 1; x < tlen; x++) { + if(buff[i + x + 1] > 0xD0) { + memcpy(app->card_number, &buff[i], x + 1); + app->card_number_len = x + 1; + app->exp_year = (buff[i + x + 1] << 4) | (buff[i + x + 2] >> 4); + app->exp_month = (buff[i + x + 2] << 4) | (buff[i + x + 3] >> 4); + break; + } + } + + // Convert 4-bit to ASCII representation + char track_2_equiv[41]; + uint8_t track_2_equiv_len = 0; + for(int x = 0; x < tlen; x++) { + char top = (buff[i + x] >> 4) + '0'; + char bottom = (buff[i + x] & 0x0F) + '0'; + track_2_equiv[x * 2] = top; + track_2_equiv_len++; + if(top == '?') break; + track_2_equiv[x * 2 + 1] = bottom; + track_2_equiv_len++; + if(bottom == '?') break; + } + track_2_equiv[track_2_equiv_len] = '\0'; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2_EQUIV %x : %s", tag, track_2_equiv); + break; + } + case EMV_TAG_PAN: + memcpy(app->card_number, &buff[i], tlen); + app->card_number_len = tlen; + success = true; + break; + case EMV_TAG_EXP_DATE: + app->exp_year = buff[i]; + app->exp_month = buff[i + 1]; + success = true; + break; + case EMV_TAG_CURRENCY_CODE: + app->currency_code = (buff[i] << 8 | buff[i + 1]); + success = true; + break; + case EMV_TAG_COUNTRY_CODE: + app->country_code = (buff[i] << 8 | buff[i + 1]); + success = true; + break; + } + } + i += tlen; + } + return success; +} + +EmvError emv_poller_select_ppse(EmvPoller* instance) { + EmvError error = EmvErrorNone; + + const uint8_t emv_select_ppse_cmd[] = { + 0x00, 0xA4, // SELECT ppse + 0x04, 0x00, // P1:By name, P2: empty + 0x0e, // Lc: Data length + 0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, // Data string: + 0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, // 2PAY.SYS.DDF01 (PPSE) + 0x00 // Le + }; + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + bit_buffer_copy_bytes(instance->tx_buffer, emv_select_ppse_cmd, sizeof(emv_select_ppse_cmd)); + do { + FURI_LOG_D(TAG, "Send select PPSE"); + + Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( + instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); + + if(iso14443_4a_error != Iso14443_4aErrorNone) { + FURI_LOG_E(TAG, "Failed select PPSE"); + error = emv_process_error(iso14443_4a_error); + break; + } + + emv_trace(instance, "Select PPSE answer:"); + + const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); + + if(!emv_decode_response( + buff, + bit_buffer_get_size_bytes(instance->rx_buffer), + &instance->data->emv_application)) { + error = EmvErrorProtocol; + FURI_LOG_E(TAG, "Failed to parse application"); + } + } while(false); + + return error; +} + +EmvError emv_poller_select_application(EmvPoller* instance) { + EmvError error = EmvErrorNone; + + // DELETE IT??????????????????????????????????????????????????????????????????????????????????????? + instance->data->emv_application.app_started = false; + + const uint8_t emv_select_header[] = { + 0x00, + 0xA4, // SELECT application + 0x04, + 0x00 // P1:By name, P2:First or only occurence + }; + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + // Copy header + bit_buffer_copy_bytes(instance->tx_buffer, emv_select_header, sizeof(emv_select_header)); + + // Copy AID + bit_buffer_append_byte(instance->tx_buffer, instance->data->emv_application.aid_len); + bit_buffer_append_bytes( + instance->tx_buffer, + instance->data->emv_application.aid, + instance->data->emv_application.aid_len); + bit_buffer_append_byte(instance->tx_buffer, 0x00); + + do { + FURI_LOG_D(TAG, "Start application"); + + Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( + instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); + + if(iso14443_4a_error != Iso14443_4aErrorNone) { + FURI_LOG_E(TAG, "Failed to read PAN or PDOL"); + error = emv_process_error(iso14443_4a_error); + break; + } + + emv_trace(instance, "Start application answer:"); + + const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); + + if(!emv_decode_response( + buff, + bit_buffer_get_size_bytes(instance->rx_buffer), + &instance->data->emv_application)) { + error = EmvErrorProtocol; + FURI_LOG_E(TAG, "Failed to parse application"); + break; + } + + instance->data->emv_application.app_started = true; + } while(false); + + return error; +} + +EmvError emv_poller_get_processing_options(EmvPoller* instance) { + EmvError error = EmvErrorNone; + + const uint8_t emv_gpo_header[] = {0x80, 0xA8, 0x00, 0x00}; + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + // Copy header + bit_buffer_copy_bytes(instance->tx_buffer, emv_gpo_header, sizeof(emv_gpo_header)); + + // Prepare and copy pdol parameters + APDU pdol_data = {0, {0}}; + emv_prepare_pdol(&pdol_data, &instance->data->emv_application.pdol); + + bit_buffer_append_byte(instance->tx_buffer, 0x02 + pdol_data.size); + bit_buffer_append_byte(instance->tx_buffer, 0x83); + bit_buffer_append_byte(instance->tx_buffer, pdol_data.size); + + bit_buffer_append_bytes(instance->tx_buffer, pdol_data.data, pdol_data.size); + bit_buffer_append_byte(instance->tx_buffer, 0x00); + + do { + FURI_LOG_D(TAG, "Get proccessing options"); + + Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( + instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); + + if(iso14443_4a_error != Iso14443_4aErrorNone) { + FURI_LOG_E(TAG, "Failed to get processing options"); + error = emv_process_error(iso14443_4a_error); + break; + } + + emv_trace(instance, "Get processing options answer:"); + + const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); + + if(!emv_decode_response( + buff, + bit_buffer_get_size_bytes(instance->rx_buffer), + &instance->data->emv_application)) { + error = EmvErrorProtocol; + FURI_LOG_E(TAG, "Failed to parse processing options"); + } + } while(false); + + return error; +} + +EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t record_num) { + EmvError error = EmvErrorNone; + + uint8_t sfi_param = (sfi << 3) | (1 << 2); + uint8_t emv_sfi_header[] = { + 0x00, + 0xB2, // READ RECORD + record_num, // P1:record_number + sfi_param, // P2:SFI + 0x00 // Le + }; + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + bit_buffer_copy_bytes(instance->tx_buffer, emv_sfi_header, sizeof(emv_sfi_header)); + + do { + Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( + instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); + + if(iso14443_4a_error != Iso14443_4aErrorNone) { + error = emv_process_error(iso14443_4a_error); + break; + } + + emv_trace(instance, "SFI record:"); + + const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); + + if(!emv_decode_response( + buff, + bit_buffer_get_size_bytes(instance->rx_buffer), + &instance->data->emv_application)) { + error = EmvErrorProtocol; + FURI_LOG_E(TAG, "Failed to read SFI record %d", record_num); + } + } while(false); + + return error; +} + +EmvError emv_poller_read_files(EmvPoller* instance) { + EmvError error = EmvErrorNone; + + APDU* afl = &instance->data->emv_application.afl; + + if(afl->size == 0) { + return false; + } + + FURI_LOG_D(TAG, "Search PAN in SFI"); + + // Iterate through all files + for(size_t i = 0; i < instance->data->emv_application.afl.size; i += 4) { + uint8_t sfi = afl->data[i] >> 3; + uint8_t record_start = afl->data[i + 1]; + uint8_t record_end = afl->data[i + 2]; + // Iterate through all records in file + for(uint8_t record = record_start; record <= record_end; ++record) { + error |= emv_poller_read_sfi_record(instance, sfi, record); + } + } + + return error; +} + +EmvError emv_poller_read(EmvPoller* instance) { + furi_assert(instance); + EmvError error = EmvErrorNone; + + memset(&instance->data->emv_application, 0, sizeof(EmvApplication)); + do { + error |= emv_poller_select_ppse(instance); + if(error != EmvErrorNone) break; + + error |= emv_poller_select_application(instance); + if(error != EmvErrorNone) break; + + if(emv_poller_get_processing_options(instance) != EmvErrorNone) + error = emv_poller_read_files(instance); + + } while(false); + + return error; +} \ No newline at end of file diff --git a/lib/nfc/protocols/emv/emv_poller_i.h b/lib/nfc/protocols/emv/emv_poller_i.h new file mode 100644 index 000000000..4809a8668 --- /dev/null +++ b/lib/nfc/protocols/emv/emv_poller_i.h @@ -0,0 +1,52 @@ +#pragma once + +#include "emv_poller.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + EmvPollerStateIdle, + EmvPollerStateSelectPPSE, + EmvPollerStateSelectApplication, + EmvPollerStateGetProcessingOptions, + EmvPollerStateReadFiles, + EmvPollerStateReadFailed, + EmvPollerStateReadSuccess, + + EmvPollerStateNum, +} EmvPollerState; + +typedef enum { + EmvPollerSessionStateIdle, + EmvPollerSessionStateActive, + EmvPollerSessionStateStopRequest, +} EmvPollerSessionState; + +struct EmvPoller { + Iso14443_4aPoller* iso14443_4a_poller; + EmvPollerSessionState session_state; + EmvPollerState state; + EmvError error; + EmvData* data; + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + BitBuffer* input_buffer; + BitBuffer* result_buffer; + EmvPollerEventData emv_event_data; + EmvPollerEvent emv_event; + NfcGenericEvent general_event; + NfcGenericCallback callback; + void* context; +}; + +EmvError emv_process_error(Iso14443_4aError error); + +const EmvData* emv_poller_get_data(EmvPoller* instance); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfc_poller_defs.c b/lib/nfc/protocols/nfc_poller_defs.c index 7553c74de..55a59cfd6 100644 --- a/lib/nfc/protocols/nfc_poller_defs.c +++ b/lib/nfc/protocols/nfc_poller_defs.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -22,6 +23,7 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = { [NfcProtocolMfUltralight] = &mf_ultralight_poller, [NfcProtocolMfClassic] = &mf_classic_poller, [NfcProtocolMfDesfire] = &mf_desfire_poller, + [NfcProtocolEmv] = &emv_poller, [NfcProtocolSlix] = &nfc_poller_slix, /* Add new pollers here */ [NfcProtocolSt25tb] = &nfc_poller_st25tb, diff --git a/lib/nfc/protocols/nfc_protocol.c b/lib/nfc/protocols/nfc_protocol.c index 2ea9b3982..54ee5ba0d 100644 --- a/lib/nfc/protocols/nfc_protocol.c +++ b/lib/nfc/protocols/nfc_protocol.c @@ -12,17 +12,19 @@ * ``` * **************************** Protocol tree structure *************************** * - * (Start) - * | - * +------------------------+-----------+---------+------------+ - * | | | | | - * ISO14443-3A ISO14443-3B Felica ISO15693-3 ST25TB - * | | | - * +---------------+-------------+ ISO14443-4B SLIX - * | | | - * ISO14443-4A Mf Ultralight Mf Classic - * | - * Mf Desfire + * (Start) + * | + * +------------------------+-----------+---------+------------+ + * | | | | | + * ISO14443-3A ISO14443-3B Felica ISO15693-3 ST25TB + * | | | + * +---------------+-------------+ ISO14443-4B SLIX + * | | | + * ISO14443-4A Mf Ultralight Mf Classic + * | + * +-----+-----+ + * | | + * Mf Desfire EMV * ``` * * When implementing a new protocol, its place in the tree must be determined first. @@ -61,6 +63,7 @@ static const NfcProtocol nfc_protocol_iso14443_3b_children_protocol[] = { /** List of ISO14443-4A child protocols. */ static const NfcProtocol nfc_protocol_iso14443_4a_children_protocol[] = { NfcProtocolMfDesfire, + NfcProtocolEmv, }; /** List of ISO115693-3 child protocols. */ @@ -134,6 +137,12 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = { .children_num = 0, .children_protocol = NULL, }, + [NfcProtocolEmv] = + { + .parent_protocol = NfcProtocolIso14443_4a, + .children_num = 0, + .children_protocol = NULL, + }, [NfcProtocolSlix] = { .parent_protocol = NfcProtocolIso15693_3, diff --git a/lib/nfc/protocols/nfc_protocol.h b/lib/nfc/protocols/nfc_protocol.h index ee6345333..d597de152 100644 --- a/lib/nfc/protocols/nfc_protocol.h +++ b/lib/nfc/protocols/nfc_protocol.h @@ -72,19 +72,19 @@ * * ### 2.2 File structure explanation * - * | Filename | Explanation | - * |:------------------------------|:------------| - * | protocol_name.h | Main protocol data structure and associated functions declarations. It is recommended to keep the former as opaque pointer. | - * | protocol_name.c | Implementations of functions declared in `protocol_name.h`. | - * | protocol_name_device_defs.h | Declarations for use by the NfcDevice library. See nfc_device_base_i.h for more info. | - * | protocol_name_poller.h | Protocol-specific poller and associated functions declarations. | - * | protocol_name_poller.c | Implementation of functions declared in `protocol_name_poller.h`. | - * | protocol_name_poller_defs.h | Declarations for use by the NfcPoller library. See nfc_poller_base.h for more info. | - * | protocol_name_listener.h | Protocol-specific listener and associated functions declarations. Optional, needed for emulation support. | - * | protocol_name_listener.c | Implementation of functions declared in `protocol_name_listener.h`. Optional, needed for emulation support. | + * | Filename | Explanation | + * |:------------------------------|:--------------------------------------------------------------------------------------------------------------------------------| + * | protocol_name.h | Main protocol data structure and associated functions declarations. It is recommended to keep the former as opaque pointer. | + * | protocol_name.c | Implementations of functions declared in `protocol_name.h`. | + * | protocol_name_device_defs.h | Declarations for use by the NfcDevice library. See nfc_device_base_i.h for more info. | + * | protocol_name_poller.h | Protocol-specific poller and associated functions declarations. | + * | protocol_name_poller.c | Implementation of functions declared in `protocol_name_poller.h`. | + * | protocol_name_poller_defs.h | Declarations for use by the NfcPoller library. See nfc_poller_base.h for more info. | + * | protocol_name_listener.h | Protocol-specific listener and associated functions declarations. Optional, needed for emulation support. | + * | protocol_name_listener.c | Implementation of functions declared in `protocol_name_listener.h`. Optional, needed for emulation support. | * | protocol_name_listener_defs.h | Declarations for use by the NfcListener library. See nfc_listener_base.h for more info. Optional, needed for emulation support. | - * | protocol_name_sync.h | Synchronous API declarations. (See below for sync API explanation). Optional.| - * | protocol_name_sync.c | Synchronous API implementation. Optional. | + * | protocol_name_sync.h | Synchronous API declarations. (See below for sync API explanation). Optional. | + * | protocol_name_sync.c | Synchronous API implementation. Optional. | * * ## 3 Implement the code * @@ -185,6 +185,7 @@ typedef enum { NfcProtocolMfUltralight, NfcProtocolMfClassic, NfcProtocolMfDesfire, + NfcProtocolEmv, NfcProtocolSlix, NfcProtocolSt25tb, /* Add new protocols here */ From cfb974dc1f5bff1d46a0483741b2b8f4726cdda3 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 10 Jan 2024 19:23:34 +0300 Subject: [PATCH 045/110] Change MIFARE name accroding to new requirements --- .../main/nfc/helpers/mf_classic_key_cache.c | 2 +- .../main/nfc/scenes/nfc_scene_extra_actions.c | 2 +- lib/nfc/helpers/nfc_data_generator.c | 20 +++++++++---------- lib/nfc/protocols/mf_classic/mf_classic.c | 12 +++++------ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/applications/main/nfc/helpers/mf_classic_key_cache.c b/applications/main/nfc/helpers/mf_classic_key_cache.c index 5127e6452..b28095110 100644 --- a/applications/main/nfc/helpers/mf_classic_key_cache.c +++ b/applications/main/nfc/helpers/mf_classic_key_cache.c @@ -58,7 +58,7 @@ bool mf_classic_key_cache_save(MfClassicKeyCache* instance, const MfClassicData* ff, mf_classic_key_cache_file_header, mf_classic_key_cache_file_version)) break; if(!flipper_format_write_string_cstr( - ff, "Mifare Classic type", mf_classic_get_device_name(data, NfcDeviceNameTypeShort))) + ff, "MIFARE Classic type", mf_classic_get_device_name(data, NfcDeviceNameTypeShort))) break; if(!flipper_format_write_hex_uint64(ff, "Key A map", &data->key_a_mask, 1)) break; if(!flipper_format_write_hex_uint64(ff, "Key B map", &data->key_b_mask, 1)) break; diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 721919d2b..d14f80b62 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -24,7 +24,7 @@ void nfc_scene_extra_actions_on_enter(void* context) { instance); submenu_add_item( submenu, - "Mifare Classic Keys", + "MIFARE Classic Keys", SubmenuIndexMfClassicKeys, nfc_scene_extra_actions_submenu_callback, instance); diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index 21f062605..0fb7062ff 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -482,27 +482,27 @@ static void nfc_generate_mf_classic_4k_7b_uid(NfcDevice* nfc_device) { static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = { [NfcDataGeneratorTypeMfUltralight] = { - .name = "Mifare Ultralight", + .name = "MIFARE Ultralight", .handler = nfc_generate_mf_ul_orig, }, [NfcDataGeneratorTypeMfUltralightEV1_11] = { - .name = "Mifare Ultralight EV1 11", + .name = "MIFARE Ultralight EV1 11", .handler = nfc_generate_mf_ul_11, }, [NfcDataGeneratorTypeMfUltralightEV1_H11] = { - .name = "Mifare Ultralight EV1 H11", + .name = "MIFARE Ultralight EV1 H11", .handler = nfc_generate_mf_ul_h11, }, [NfcDataGeneratorTypeMfUltralightEV1_21] = { - .name = "Mifare Ultralight EV1 21", + .name = "MIFARE Ultralight EV1 21", .handler = nfc_generate_mf_ul_21, }, [NfcDataGeneratorTypeMfUltralightEV1_H21] = { - .name = "Mifare Ultralight EV1 H21", + .name = "MIFARE Ultralight EV1 H21", .handler = nfc_generate_mf_ul_h21, }, [NfcDataGeneratorTypeNTAG203] = @@ -547,27 +547,27 @@ static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = { }, [NfcDataGeneratorTypeMfClassicMini] = { - .name = "Mifare Mini", + .name = "MIFARE Mini", .handler = nfc_generate_mf_classic_mini, }, [NfcDataGeneratorTypeMfClassic1k_4b] = { - .name = "Mifare Classic 1k 4byte UID", + .name = "MIFARE Classic 1k 4byte UID", .handler = nfc_generate_mf_classic_1k_4b_uid, }, [NfcDataGeneratorTypeMfClassic1k_7b] = { - .name = "Mifare Classic 1k 7byte UID", + .name = "MIFARE Classic 1k 7byte UID", .handler = nfc_generate_mf_classic_1k_7b_uid, }, [NfcDataGeneratorTypeMfClassic4k_4b] = { - .name = "Mifare Classic 4k 4byte UID", + .name = "MIFARE Classic 4k 4byte UID", .handler = nfc_generate_mf_classic_4k_4b_uid, }, [NfcDataGeneratorTypeMfClassic4k_7b] = { - .name = "Mifare Classic 4k 7byte UID", + .name = "MIFARE Classic 4k 7byte UID", .handler = nfc_generate_mf_classic_4k_7b_uid, }, }; diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index e68e8c718..e9dfb28f4 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -21,21 +21,21 @@ static const MfClassicFeatures mf_classic_features[MfClassicTypeNum] = { { .sectors_total = 5, .blocks_total = 20, - .full_name = "Mifare Classic Mini 0.3K", + .full_name = "MIFARE Classic Mini 0.3K", .type_name = "MINI", }, [MfClassicType1k] = { .sectors_total = 16, .blocks_total = 64, - .full_name = "Mifare Classic 1K", + .full_name = "MIFARE Classic 1K", .type_name = "1K", }, [MfClassicType4k] = { .sectors_total = 40, .blocks_total = 256, - .full_name = "Mifare Classic 4K", + .full_name = "MIFARE Classic 4K", .type_name = "4K", }, }; @@ -261,15 +261,15 @@ bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff) { do { if(!iso14443_3a_save(data->iso14443_3a_data, ff)) break; - if(!flipper_format_write_comment_cstr(ff, "Mifare Classic specific data")) break; + if(!flipper_format_write_comment_cstr(ff, "MIFARE Classic specific data")) break; if(!flipper_format_write_string_cstr( - ff, "Mifare Classic type", mf_classic_features[data->type].type_name)) + ff, "MIFARE Classic type", mf_classic_features[data->type].type_name)) break; if(!flipper_format_write_uint32( ff, "Data format version", &mf_classic_data_format_version, 1)) break; if(!flipper_format_write_comment_cstr( - ff, "Mifare Classic blocks, \'??\' means unknown data")) + ff, "MIFARE Classic blocks, \'??\' means unknown data")) break; uint16_t blocks_total = mf_classic_get_total_block_num(data->type); From 686fd208dcd3cf859c1797f38d2ecf197f81ce75 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 10 Jan 2024 19:34:07 +0300 Subject: [PATCH 046/110] New QR code image for MFKey app --- assets/icons/NFC/MFKey_qr_25x25.png | Bin 0 -> 218 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/icons/NFC/MFKey_qr_25x25.png diff --git a/assets/icons/NFC/MFKey_qr_25x25.png b/assets/icons/NFC/MFKey_qr_25x25.png new file mode 100644 index 0000000000000000000000000000000000000000..feb07e2807e7e116bcbd76b48e5555a4c48dc7a1 GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%3?x6Bmj(hUwg8_HS0MfW|No^o=iddg`aNA7 zLn>~i1TqR8P~d3#Utcx5>%rMDZBr+fTM?gSRZ{+}sksq*TzU3X_G(3uq)mQDZhSMV z@_o$KFX5THNn&|Yaa_i)=;WZqcju(8 Date: Wed, 10 Jan 2024 19:34:40 +0300 Subject: [PATCH 047/110] Update nfc_scene_mf_classic_mfkey_complete.c scene according to new UI requirements --- .../scenes/nfc_scene_mf_classic_mfkey_complete.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c index 8e07043e2..eb0aa7c3a 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c @@ -18,15 +18,16 @@ void nfc_scene_mf_classic_mfkey_complete_on_enter(void* context) { widget_add_string_multiline_element( instance->widget, 64, - 32, - AlignCenter, + 13, AlignCenter, + AlignTop, FontSecondary, - "Now use Mfkey32\nto extract keys"); + "Now use Mfkey32 to extract \nkeys: lab.flipper.net/nfc-tools"); + widget_add_icon_element(instance->widget, 50, 39, &I_MFKey_qr_25x25); widget_add_button_element( instance->widget, - GuiButtonTypeCenter, - "OK", + GuiButtonTypeRight, + "Finish", nfc_scene_mf_classic_mfkey_complete_callback, instance); @@ -38,7 +39,7 @@ bool nfc_scene_mf_classic_mfkey_complete_on_event(void* context, SceneManagerEve bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeCenter) { + if(event.event == GuiButtonTypeRight) { consumed = scene_manager_search_and_switch_to_previous_scene( instance->scene_manager, NfcSceneStart); } From 85f437ee221a7a4de65646a6f5536173dea4940f Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 10 Jan 2024 20:24:12 +0300 Subject: [PATCH 048/110] Update detect_reader.c and check_big_20x17.png --- applications/main/nfc/views/detect_reader.c | 2 +- assets/icons/NFC/check_big_20x17.png | Bin 199 -> 994 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/views/detect_reader.c b/applications/main/nfc/views/detect_reader.c index d832d27d6..4d7b324e0 100644 --- a/applications/main/nfc/views/detect_reader.c +++ b/applications/main/nfc/views/detect_reader.c @@ -50,7 +50,7 @@ static void detect_reader_draw_callback(Canvas* canvas, void* model) { if(m->state == DetectReaderStateDone) { canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 51, 22, AlignLeft, AlignTop, "Completed!"); - canvas_draw_icon(canvas, 20, 23, &I_check_big_20x17); + canvas_draw_icon(canvas, 24, 23, &I_check_big_20x17); } else { canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 51, 22, AlignLeft, AlignTop, "Collecting..."); diff --git a/assets/icons/NFC/check_big_20x17.png b/assets/icons/NFC/check_big_20x17.png index c74e5b1c319b11eba22a03af828c3c8f420d5dc2..0e84cfa071cafc0e6804f154b8e22973b2952a95 100644 GIT binary patch literal 994 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz2!3-o{&8q2PU|?nl@CkAK|NlQwWE6~sz{m^% zZsqL{fj(y}3GxeOaCmkj4angv@Q5sCVBi)8VMc~ob0mO*x+Sg=CBgY=CFO}lsSM6V zsfi`2DGEuI3Te*yDXB#Y?nQ|O8JWq&3IRp=$*IM~`9<}I-^K$qI(fP{hE&|D?PcU* zP~c#e{qkR5|MY^WmkA2TAI|c8kjwS9^@rnWh5U{)PZ}bQe_N%vLt2j8c+Tb1^+9{G e<`%~c+~R3zcok>&>S`_TF9C gbmIB1#PS~u`_;J>%r~*R04-whboFyt=akR{02j7K1^@s6 From e9454b629b7853b0ca374871c2fa3015c5774f4e Mon Sep 17 00:00:00 2001 From: Methodius Date: Thu, 11 Jan 2024 18:11:54 +0900 Subject: [PATCH 049/110] NFC fap: EMV protocol added --- .../nfc/helpers/protocol_support/emv/emv.c | 115 ++++++++++++++++++ .../nfc/helpers/protocol_support/emv/emv.h | 5 + .../helpers/protocol_support/emv/emv_render.c | 35 ++++++ .../helpers/protocol_support/emv/emv_render.h | 16 +++ .../nfc_protocol_support_defs.c | 2 + .../main/nfc/scenes/nfc_scene_config.h | 2 + .../main/nfc/scenes/nfc_scene_emv_more_info.c | 75 ++++++++++++ lib/nfc/SConscript | 2 + lib/nfc/protocols/emv/emv.h | 4 +- lib/nfc/protocols/emv/emv_poller_i.c | 8 +- targets/f7/api_symbols.csv | 24 +++- 11 files changed, 281 insertions(+), 7 deletions(-) create mode 100644 applications/main/nfc/helpers/protocol_support/emv/emv.c create mode 100644 applications/main/nfc/helpers/protocol_support/emv/emv.h create mode 100644 applications/main/nfc/helpers/protocol_support/emv/emv_render.c create mode 100644 applications/main/nfc/helpers/protocol_support/emv/emv_render.h create mode 100644 applications/main/nfc/scenes/nfc_scene_emv_more_info.c diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv.c b/applications/main/nfc/helpers/protocol_support/emv/emv.c new file mode 100644 index 000000000..035f8d220 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/emv/emv.c @@ -0,0 +1,115 @@ +#include "emv.h" +#include "emv_render.h" + +#include + +#include "nfc/nfc_app_i.h" + +#include "../nfc_protocol_support_common.h" +#include "../nfc_protocol_support_gui_common.h" +#include "../iso14443_4a/iso14443_4a_i.h" + +static void nfc_scene_info_on_enter_emv(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_emv_info(data, NfcProtocolFormatTypeFull, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static void nfc_scene_more_info_on_enter_emv(NfcApp* instance) { + // Jump to advanced scene right away + scene_manager_next_scene(instance->scene_manager, NfcSceneEmvMoreInfo); +} + +static NfcCommand nfc_scene_read_poller_callback_emv(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolEmv); + + NfcApp* instance = context; + const EmvPollerEvent* emv_event = event.event_data; + + if(emv_event->type == EmvPollerEventTypeReadSuccess) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolEmv, nfc_poller_get_data(instance->poller)); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); + return NfcCommandStop; + } + + return NfcCommandContinue; +} + +static void nfc_scene_read_on_enter_emv(NfcApp* instance) { + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_emv, instance); +} + +static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_emv_info(data, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +// static void nfc_scene_emulate_on_enter_emv(NfcApp* instance) { +// const Iso14443_4aData* iso14443_4a_data = +// nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_4a); + +// instance->listener = +// nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_4a, iso14443_4a_data); +// nfc_listener_start( +// instance->listener, nfc_scene_emulate_listener_callback_iso14443_4a, instance); +// } + +const NfcProtocolSupportBase nfc_protocol_support_emv = { + .features = NfcProtocolFeatureNone, + + .scene_info = + { + .on_enter = nfc_scene_info_on_enter_emv, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_more_info = + { + .on_enter = nfc_scene_more_info_on_enter_emv, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_read = + { + .on_enter = nfc_scene_read_on_enter_emv, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_read_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_read_success = + { + .on_enter = nfc_scene_read_success_on_enter_emv, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_saved_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_save_name = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, +}; diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv.h b/applications/main/nfc/helpers/protocol_support/emv/emv.h new file mode 100644 index 000000000..c68564f36 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/emv/emv.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase nfc_protocol_support_emv; diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c new file mode 100644 index 000000000..46cdc974f --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -0,0 +1,35 @@ +#include "emv_render.h" + +#include "../iso14443_4a/iso14443_4a_render.h" + +void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str) { + nfc_render_iso14443_4a_brief(emv_get_base_data(data), str); + + nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str); + nfc_render_emv_name(data->emv_application.name, str); + + if(format_type != NfcProtocolFormatTypeFull) return; + + furi_string_cat(str, "\n\e#ISO14443-4 data"); + nfc_render_iso14443_4a_extra(emv_get_base_data(data), str); +} + +void nfc_render_emv_data(const EmvData* data, FuriString* str) { + nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str); + nfc_render_emv_name(data->emv_application.name, str); +} + +void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str) { + for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%u", data[i]); + furi_string_cat_printf(str, "\n"); +} + +void nfc_render_emv_name(const char* data, FuriString* str) { + UNUSED(data); + furi_string_cat_printf(str, "\n"); +} + +void nfc_render_emv_application(const EmvApplication* data, FuriString* str) { + UNUSED(data); + furi_string_cat_printf(str, "\n"); +} \ No newline at end of file diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h new file mode 100644 index 000000000..16fc2e172 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "../nfc_protocol_support_render_common.h" +#include + +void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str); + +void nfc_render_emv_data(const EmvData* data, FuriString* str); + +void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str); + +void nfc_render_emv_name(const char* data, FuriString* str); + +void nfc_render_emv_application(const EmvApplication* data, FuriString* str); \ No newline at end of file diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c index 215ffc455..9e61585c9 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c @@ -18,6 +18,7 @@ #include "mf_ultralight/mf_ultralight.h" #include "mf_classic/mf_classic.h" #include "mf_desfire/mf_desfire.h" +#include "emv/emv.h" #include "slix/slix.h" #include "st25tb/st25tb.h" @@ -39,6 +40,7 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = { [NfcProtocolMfUltralight] = &nfc_protocol_support_mf_ultralight, [NfcProtocolMfClassic] = &nfc_protocol_support_mf_classic, [NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire, + [NfcProtocolEmv] = &nfc_protocol_support_emv, [NfcProtocolSlix] = &nfc_protocol_support_slix, [NfcProtocolSt25tb] = &nfc_protocol_support_st25tb, /* Add new protocol support implementations here */ diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a9887996d..c0e28f480 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -36,6 +36,8 @@ ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) ADD_SCENE(nfc, mf_desfire_more_info, MfDesfireMoreInfo) ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) +ADD_SCENE(nfc, emv_more_info, EmvMoreInfo) + ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) ADD_SCENE(nfc, mf_classic_detect_reader, MfClassicDetectReader) ADD_SCENE(nfc, mf_classic_mfkey_nonces_info, MfClassicMfkeyNoncesInfo) diff --git a/applications/main/nfc/scenes/nfc_scene_emv_more_info.c b/applications/main/nfc/scenes/nfc_scene_emv_more_info.c new file mode 100644 index 000000000..5825190d1 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_emv_more_info.c @@ -0,0 +1,75 @@ +#include "../nfc_app_i.h" + +#include "../helpers/protocol_support/nfc_protocol_support_gui_common.h" +#include "../helpers/protocol_support/emv/emv_render.h" + +enum { + EmvMoreInfoStateMenu, + EmvMoreInfoStateItem, // MUST be last, states >= this correspond with submenu index +}; + +enum SubmenuIndex { + SubmenuIndexCardInfo, + SubmenuIndexDynamic, // dynamic indices start here +}; + +void nfc_scene_emv_more_info_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + text_box_set_font(nfc->text_box, TextBoxFontHex); + + submenu_add_item( + submenu, + "Card info", + SubmenuIndexCardInfo, + nfc_protocol_support_common_submenu_callback, + nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_emv_more_info_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + const uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmvMoreInfo); + const EmvData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolEmv); + + if(event.type == SceneManagerEventTypeCustom) { + TextBox* text_box = nfc->text_box; + furi_string_reset(nfc->text_box_store); + + if(event.event == SubmenuIndexCardInfo) { + nfc_render_emv_data(data, nfc->text_box_store); + text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + scene_manager_set_scene_state( + nfc->scene_manager, + NfcSceneEmvMoreInfo, + EmvMoreInfoStateItem + SubmenuIndexCardInfo); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state >= EmvMoreInfoStateItem) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmvMoreInfo, EmvMoreInfoStateMenu); + } else { + // Return directly to the Info scene + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneInfo); + } + consumed = true; + } + + return consumed; +} + +void nfc_scene_emv_more_info_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear views + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + submenu_reset(nfc->submenu); +} diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 41332362c..3ad62f322 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -22,6 +22,7 @@ env.Append( File("protocols/mf_ultralight/mf_ultralight.h"), File("protocols/mf_classic/mf_classic.h"), File("protocols/mf_desfire/mf_desfire.h"), + File("protocols/emv/emv.h"), File("protocols/slix/slix.h"), File("protocols/st25tb/st25tb.h"), # Pollers @@ -32,6 +33,7 @@ env.Append( File("protocols/mf_ultralight/mf_ultralight_poller.h"), File("protocols/mf_classic/mf_classic_poller.h"), File("protocols/mf_desfire/mf_desfire_poller.h"), + File("protocols/emv/emv_poller.h"), File("protocols/st25tb/st25tb_poller.h"), # Listeners File("protocols/iso14443_3a/iso14443_3a_listener.h"), diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index feb390c7d..253101df7 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -41,8 +41,8 @@ typedef struct { bool app_started; char name[32]; bool name_found; - uint8_t card_number[10]; - uint8_t card_number_len; + uint8_t pan[10]; + uint8_t pan_len; uint8_t exp_month; uint8_t exp_year; uint16_t country_code; diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 22c862661..4bb85eab7 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -186,8 +186,8 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio // 0xD0 delimits PAN from expiry (YYMM) for(int x = 1; x < tlen; x++) { if(buff[i + x + 1] > 0xD0) { - memcpy(app->card_number, &buff[i], x + 1); - app->card_number_len = x + 1; + memcpy(app->pan, &buff[i], x + 1); + app->pan_len = x + 1; app->exp_year = (buff[i + x + 1] << 4) | (buff[i + x + 2] >> 4); app->exp_month = (buff[i + x + 2] << 4) | (buff[i + x + 3] >> 4); break; @@ -213,8 +213,8 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio break; } case EMV_TAG_PAN: - memcpy(app->card_number, &buff[i], tlen); - app->card_number_len = tlen; + memcpy(app->pan, &buff[i], tlen); + app->pan_len = tlen; success = true; break; case EMV_TAG_EXP_DATE: diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 0ce105b05..1857a77ca 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,50.1,, +Version,v,50.2,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -120,6 +120,8 @@ Header,+,lib/nfc/nfc_device.h,, Header,+,lib/nfc/nfc_listener.h,, Header,+,lib/nfc/nfc_poller.h,, Header,+,lib/nfc/nfc_scanner.h,, +Header,?,lib/nfc/protocols/emv/emv.h,, +Header,?,lib/nfc/protocols/emv/emv_poller.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h,, @@ -877,6 +879,25 @@ Function,+,elf_symbolname_hash,uint32_t,const char* Function,+,empty_screen_alloc,EmptyScreen*, Function,+,empty_screen_free,void,EmptyScreen* Function,+,empty_screen_get_view,View*,EmptyScreen* +Function,?,emv_alloc,EmvData*, +Function,?,emv_copy,void,"EmvData*, const EmvData*" +Function,?,emv_free,void,EmvData* +Function,?,emv_get_application,const EmvApplication*,const EmvData* +Function,?,emv_get_base_data,Iso14443_4aData*,const EmvData* +Function,?,emv_get_device_name,const char*,"const EmvData*, NfcDeviceNameType" +Function,?,emv_get_uid,const uint8_t*,"const EmvData*, size_t*" +Function,?,emv_is_equal,_Bool,"const EmvData*, const EmvData*" +Function,?,emv_load,_Bool,"EmvData*, FlipperFormat*, uint32_t" +Function,?,emv_poller_get_processing_options,EmvError,EmvPoller* +Function,?,emv_poller_read,EmvError,EmvPoller* +Function,?,emv_poller_read_files,EmvError,EmvPoller* +Function,?,emv_poller_read_sfi_record,EmvError,"EmvPoller*, uint8_t, uint8_t" +Function,?,emv_poller_select_application,EmvError,EmvPoller* +Function,?,emv_poller_select_ppse,EmvError,EmvPoller* +Function,?,emv_reset,void,EmvData* +Function,?,emv_save,_Bool,"const EmvData*, FlipperFormat*" +Function,?,emv_set_uid,_Bool,"EmvData*, const uint8_t*, size_t" +Function,?,emv_verify,_Bool,"EmvData*, const FuriString*" Function,-,erand48,double,unsigned short[3] Function,-,erf,double,double Function,-,erfc,double,double @@ -3619,6 +3640,7 @@ Variable,+,message_red_255,const NotificationMessage, Variable,+,message_sound_off,const NotificationMessage, Variable,+,message_vibro_off,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage, +Variable,?,nfc_device_emv,const NfcDeviceBase, Variable,-,nfc_device_mf_classic,const NfcDeviceBase, Variable,-,nfc_device_mf_desfire,const NfcDeviceBase, Variable,-,nfc_device_mf_ultralight,const NfcDeviceBase, From 4397e2cff5842cf3b1afb26c90dec7302bb60e67 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 11 Jan 2024 20:21:54 +0300 Subject: [PATCH 050/110] New nfc save confirm scene added --- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../main/nfc/scenes/nfc_scene_save_confirm.c | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 applications/main/nfc/scenes/nfc_scene_save_confirm.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a9887996d..70e7c3d46 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -23,6 +23,7 @@ ADD_SCENE(nfc, debug, Debug) ADD_SCENE(nfc, field, Field) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) +ADD_SCENE(nfc, save_confirm, SaveConfirm) ADD_SCENE(nfc, mf_ultralight_write, MfUltralightWrite) ADD_SCENE(nfc, mf_ultralight_write_success, MfUltralightWriteSuccess) diff --git a/applications/main/nfc/scenes/nfc_scene_save_confirm.c b/applications/main/nfc/scenes/nfc_scene_save_confirm.c new file mode 100644 index 000000000..9d0a206d3 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_save_confirm.c @@ -0,0 +1,44 @@ +#include "../nfc_app_i.h" + +void nfc_scene_save_confirm_dialog_callback(DialogExResult result, void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_save_confirm_on_enter(void* context) { + NfcApp* nfc = context; + DialogEx* dialog_ex = nfc->dialog_ex; + + dialog_ex_set_left_button_text(dialog_ex, "Skip"); + dialog_ex_set_right_button_text(dialog_ex, "Save"); + dialog_ex_set_header(dialog_ex, "Save the Key?", 64, 0, AlignCenter, AlignTop); + dialog_ex_set_text(dialog_ex, "All unsaved data will be lost", 64, 12, AlignCenter, AlignTop); + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_save_confirm_dialog_callback); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +bool nfc_scene_save_confirm_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } else if(event.event == DialogExResultLeft) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDetectReader); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_save_confirm_on_exit(void* context) { + NfcApp* nfc = context; + + // Clean view + dialog_ex_reset(nfc->dialog_ex); +} From d3c994c4034cfdfeb014242b9ba0c95bce001024 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 11 Jan 2024 20:23:13 +0300 Subject: [PATCH 051/110] Implemented new flow for 'Detect Reader button' after partial mf classic read according to new UI --- .../nfc/helpers/protocol_support/mf_classic/mf_classic.c | 2 +- .../main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c | 7 +++++++ applications/main/nfc/scenes/nfc_scene_save_success.c | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index 3e0468cd9..97913b9d2 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -168,7 +168,7 @@ static void nfc_scene_emulate_on_enter_mf_classic(NfcApp* instance) { static bool nfc_scene_read_menu_on_event_mf_classic(NfcApp* instance, uint32_t event) { if(event == SubmenuIndexDetectReader) { - scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicDetectReader); + scene_manager_next_scene(instance->scene_manager, NfcSceneSaveConfirm); dolphin_deed(DolphinDeedNfcDetectReader); return true; } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c index 987f81837..e2d3e6d72 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c @@ -134,6 +134,13 @@ bool nfc_scene_mf_classic_detect_reader_on_event(void* context, SceneManagerEven instance->listener = NULL; } mfkey32_logger_free(instance->mfkey32_logger); + if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSaveSuccess)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneStart); + } else if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneReadSuccess)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneReadSuccess); + } } return consumed; diff --git a/applications/main/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c index 9d2a38013..ef7863c13 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc/scenes/nfc_scene_save_success.c @@ -28,6 +28,9 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneMfClassicKeys); + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSaveConfirm)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDetectReader); + consumed = true; } else { consumed = scene_manager_search_and_switch_to_another_scene( nfc->scene_manager, NfcSceneFileSelect); From e8b468b492f81650a55eabdbcd72e7e4a1f6b6d2 Mon Sep 17 00:00:00 2001 From: Methodius Date: Fri, 12 Jan 2024 17:08:34 +0900 Subject: [PATCH 052/110] EMV Poller fix --- lib/nfc/protocols/emv/emv.c | 1 + lib/nfc/protocols/emv/emv.h | 2 +- lib/nfc/protocols/emv/emv_poller.h | 6 +++- lib/nfc/protocols/nfc_device_defs.c | 2 ++ targets/f7/api_symbols.csv | 45 ++++++++++++++--------------- 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index 2de6fb132..2a6c83101 100644 --- a/lib/nfc/protocols/emv/emv.c +++ b/lib/nfc/protocols/emv/emv.c @@ -4,6 +4,7 @@ #include "protocols/emv/emv.h" #include #include +#include #define EMV_PROTOCOL_NAME "EMV" diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index 253101df7..45318292b 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -93,7 +93,7 @@ Iso14443_4aData* emv_get_base_data(const EmvData* data); // Getters and tests -const EmvApplication* emv_get_application(const EmvData* data); +//const EmvApplication* emv_get_application(const EmvData* data); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/emv/emv_poller.h b/lib/nfc/protocols/emv/emv_poller.h index f86186fe2..8c053ede4 100644 --- a/lib/nfc/protocols/emv/emv_poller.h +++ b/lib/nfc/protocols/emv/emv_poller.h @@ -48,4 +48,8 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re EmvError emv_poller_read_files(EmvPoller* instance); -EmvError emv_poller_read(EmvPoller* instance); \ No newline at end of file +EmvError emv_poller_read(EmvPoller* instance); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/nfc/protocols/nfc_device_defs.c b/lib/nfc/protocols/nfc_device_defs.c index 870bcafd9..0dbe8a155 100644 --- a/lib/nfc/protocols/nfc_device_defs.c +++ b/lib/nfc/protocols/nfc_device_defs.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,7 @@ const NfcDeviceBase* nfc_devices[NfcProtocolNum] = { [NfcProtocolMfUltralight] = &nfc_device_mf_ultralight, [NfcProtocolMfClassic] = &nfc_device_mf_classic, [NfcProtocolMfDesfire] = &nfc_device_mf_desfire, + [NfcProtocolEmv] = &nfc_device_emv, [NfcProtocolSlix] = &nfc_device_slix, [NfcProtocolSt25tb] = &nfc_device_st25tb, /* Add new protocols here */ diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 1857a77ca..ad6a4c1bd 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,v,50.2,, +Version,+,50.2,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -120,8 +120,8 @@ Header,+,lib/nfc/nfc_device.h,, Header,+,lib/nfc/nfc_listener.h,, Header,+,lib/nfc/nfc_poller.h,, Header,+,lib/nfc/nfc_scanner.h,, -Header,?,lib/nfc/protocols/emv/emv.h,, -Header,?,lib/nfc/protocols/emv/emv_poller.h,, +Header,+,lib/nfc/protocols/emv/emv.h,, +Header,+,lib/nfc/protocols/emv/emv_poller.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h,, @@ -879,25 +879,24 @@ Function,+,elf_symbolname_hash,uint32_t,const char* Function,+,empty_screen_alloc,EmptyScreen*, Function,+,empty_screen_free,void,EmptyScreen* Function,+,empty_screen_get_view,View*,EmptyScreen* -Function,?,emv_alloc,EmvData*, -Function,?,emv_copy,void,"EmvData*, const EmvData*" -Function,?,emv_free,void,EmvData* -Function,?,emv_get_application,const EmvApplication*,const EmvData* -Function,?,emv_get_base_data,Iso14443_4aData*,const EmvData* -Function,?,emv_get_device_name,const char*,"const EmvData*, NfcDeviceNameType" -Function,?,emv_get_uid,const uint8_t*,"const EmvData*, size_t*" -Function,?,emv_is_equal,_Bool,"const EmvData*, const EmvData*" -Function,?,emv_load,_Bool,"EmvData*, FlipperFormat*, uint32_t" -Function,?,emv_poller_get_processing_options,EmvError,EmvPoller* -Function,?,emv_poller_read,EmvError,EmvPoller* -Function,?,emv_poller_read_files,EmvError,EmvPoller* -Function,?,emv_poller_read_sfi_record,EmvError,"EmvPoller*, uint8_t, uint8_t" -Function,?,emv_poller_select_application,EmvError,EmvPoller* -Function,?,emv_poller_select_ppse,EmvError,EmvPoller* -Function,?,emv_reset,void,EmvData* -Function,?,emv_save,_Bool,"const EmvData*, FlipperFormat*" -Function,?,emv_set_uid,_Bool,"EmvData*, const uint8_t*, size_t" -Function,?,emv_verify,_Bool,"EmvData*, const FuriString*" +Function,+,emv_alloc,EmvData*, +Function,+,emv_copy,void,"EmvData*, const EmvData*" +Function,+,emv_free,void,EmvData* +Function,+,emv_get_base_data,Iso14443_4aData*,const EmvData* +Function,+,emv_get_device_name,const char*,"const EmvData*, NfcDeviceNameType" +Function,+,emv_get_uid,const uint8_t*,"const EmvData*, size_t*" +Function,+,emv_is_equal,_Bool,"const EmvData*, const EmvData*" +Function,+,emv_load,_Bool,"EmvData*, FlipperFormat*, uint32_t" +Function,+,emv_poller_get_processing_options,EmvError,EmvPoller* +Function,+,emv_poller_read,EmvError,EmvPoller* +Function,+,emv_poller_read_files,EmvError,EmvPoller* +Function,+,emv_poller_read_sfi_record,EmvError,"EmvPoller*, uint8_t, uint8_t" +Function,+,emv_poller_select_application,EmvError,EmvPoller* +Function,+,emv_poller_select_ppse,EmvError,EmvPoller* +Function,+,emv_reset,void,EmvData* +Function,+,emv_save,_Bool,"const EmvData*, FlipperFormat*" +Function,+,emv_set_uid,_Bool,"EmvData*, const uint8_t*, size_t" +Function,+,emv_verify,_Bool,"EmvData*, const FuriString*" Function,-,erand48,double,unsigned short[3] Function,-,erf,double,double Function,-,erfc,double,double @@ -3640,7 +3639,7 @@ Variable,+,message_red_255,const NotificationMessage, Variable,+,message_sound_off,const NotificationMessage, Variable,+,message_vibro_off,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage, -Variable,?,nfc_device_emv,const NfcDeviceBase, +Variable,-,nfc_device_emv,const NfcDeviceBase, Variable,-,nfc_device_mf_classic,const NfcDeviceBase, Variable,-,nfc_device_mf_desfire,const NfcDeviceBase, Variable,-,nfc_device_mf_ultralight,const NfcDeviceBase, From bfffaf5b53d9d3893047e16532af55de2f289272 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 12 Jan 2024 13:12:32 +0300 Subject: [PATCH 053/110] UID for 15693 tags now shown on the new line --- .../helpers/protocol_support/iso15693_3/iso15693_3_render.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c index 92bdb22dc..bb2ab92d3 100644 --- a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c @@ -18,20 +18,20 @@ void nfc_render_iso15693_3_info( } void nfc_render_iso15693_3_brief(const Iso15693_3Data* data, FuriString* str) { - furi_string_cat_printf(str, "UID:"); + furi_string_cat_printf(str, "UID:\n"); size_t uid_len; const uint8_t* uid = iso15693_3_get_uid(data, &uid_len); for(size_t i = 0; i < uid_len; i++) { - furi_string_cat_printf(str, " %02X", uid[i]); + furi_string_cat_printf(str, "%02X ", uid[i]); } if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_MEMORY) { const uint16_t block_count = iso15693_3_get_block_count(data); const uint8_t block_size = iso15693_3_get_block_size(data); - furi_string_cat_printf(str, "Memory: %u bytes\n", block_count * block_size); + furi_string_cat_printf(str, "\nMemory: %u bytes\n", block_count * block_size); furi_string_cat_printf(str, "(%u blocks x %u bytes)", block_count, block_size); } } From d337222cbe0ca9fc410fe1969d44c4160621b4f1 Mon Sep 17 00:00:00 2001 From: Methodius Date: Fri, 12 Jan 2024 22:14:21 +0900 Subject: [PATCH 054/110] minor fixes --- lib/nfc/protocols/emv/emv_poller.c | 6 +++++- lib/nfc/protocols/emv/emv_poller_i.c | 14 +++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c index 46f02b363..61ef1c30e 100644 --- a/lib/nfc/protocols/emv/emv_poller.c +++ b/lib/nfc/protocols/emv/emv_poller.c @@ -27,6 +27,8 @@ static EmvPoller* emv_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller) { instance->input_buffer = bit_buffer_alloc(EMV_BUF_SIZE); instance->result_buffer = bit_buffer_alloc(EMV_RESULT_BUF_SIZE); + instance->state = EmvPollerStateIdle; + instance->emv_event.data = &instance->emv_event_data; instance->general_event.protocol = NfcProtocolEmv; @@ -63,6 +65,7 @@ static NfcCommand emv_poller_handler_idle(EmvPoller* instance) { static NfcCommand emv_poller_handler_select_ppse(EmvPoller* instance) { instance->error = emv_poller_select_ppse(instance); + if(instance->error == EmvErrorNone) { FURI_LOG_D(TAG, "Select PPSE success"); instance->state = EmvPollerStateSelectApplication; @@ -76,7 +79,8 @@ static NfcCommand emv_poller_handler_select_ppse(EmvPoller* instance) { } static NfcCommand emv_poller_handler_select_application(EmvPoller* instance) { - instance->error = emv_poller_select_ppse(instance); + instance->error = emv_poller_select_application(instance); + if(instance->error == EmvErrorNone) { FURI_LOG_D(TAG, "Select application success"); instance->state = EmvPollerStateGetProcessingOptions; diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 4bb85eab7..da8503744 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -314,14 +314,14 @@ EmvError emv_poller_select_application(EmvPoller* instance) { Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); + emv_trace(instance, "Start application answer:"); + if(iso14443_4a_error != Iso14443_4aErrorNone) { FURI_LOG_E(TAG, "Failed to read PAN or PDOL"); error = emv_process_error(iso14443_4a_error); break; } - emv_trace(instance, "Start application answer:"); - const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); if(!emv_decode_response( @@ -367,14 +367,14 @@ EmvError emv_poller_get_processing_options(EmvPoller* instance) { Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); + emv_trace(instance, "Get processing options answer:"); + if(iso14443_4a_error != Iso14443_4aErrorNone) { - FURI_LOG_E(TAG, "Failed to get processing options"); + FURI_LOG_E(TAG, "Failed to get processing options, error %u", iso14443_4a_error); error = emv_process_error(iso14443_4a_error); break; } - emv_trace(instance, "Get processing options answer:"); - const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); if(!emv_decode_response( @@ -410,13 +410,13 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); + emv_trace(instance, "SFI record:"); + if(iso14443_4a_error != Iso14443_4aErrorNone) { error = emv_process_error(iso14443_4a_error); break; } - emv_trace(instance, "SFI record:"); - const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); if(!emv_decode_response( From 685ed6bfad1980e42098a8bbe366de5b8b4cfd09 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 12 Jan 2024 17:27:22 +0300 Subject: [PATCH 055/110] Fix nfc unit tests --- lib/nfc/protocols/mf_classic/mf_classic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index e9dfb28f4..de025907d 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -5,7 +5,7 @@ #include -#define MF_CLASSIC_PROTOCOL_NAME "Mifare Classic" +#define MF_CLASSIC_PROTOCOL_NAME "MIFARE Classic" typedef struct { uint8_t sectors_total; @@ -93,7 +93,7 @@ void mf_classic_copy(MfClassicData* data, const MfClassicData* other) { bool mf_classic_verify(MfClassicData* data, const FuriString* device_type) { UNUSED(data); - return furi_string_equal_str(device_type, "Mifare Classic"); + return furi_string_equal_str(device_type, MF_CLASSIC_PROTOCOL_NAME); } static void mf_classic_parse_block(FuriString* block_str, MfClassicData* data, uint8_t block_num) { @@ -154,7 +154,7 @@ bool mf_classic_load(MfClassicData* data, FlipperFormat* ff, uint32_t version) { if(!iso14443_3a_load(data->iso14443_3a_data, ff, version)) break; // Read Mifare Classic type - if(!flipper_format_read_string(ff, "Mifare Classic type", temp_str)) break; + if(!flipper_format_read_string(ff, "MIFARE Classic type", temp_str)) break; bool type_parsed = false; for(size_t i = 0; i < MfClassicTypeNum; i++) { if(furi_string_equal_str(temp_str, mf_classic_features[i].type_name)) { From 8799e1112b2018e3e582151961d62169eaba80c8 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 12 Jan 2024 17:35:45 +0300 Subject: [PATCH 056/110] Revert "Fix nfc unit tests" This reverts commit 685ed6bfad1980e42098a8bbe366de5b8b4cfd09. --- lib/nfc/protocols/mf_classic/mf_classic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index de025907d..e9dfb28f4 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -5,7 +5,7 @@ #include -#define MF_CLASSIC_PROTOCOL_NAME "MIFARE Classic" +#define MF_CLASSIC_PROTOCOL_NAME "Mifare Classic" typedef struct { uint8_t sectors_total; @@ -93,7 +93,7 @@ void mf_classic_copy(MfClassicData* data, const MfClassicData* other) { bool mf_classic_verify(MfClassicData* data, const FuriString* device_type) { UNUSED(data); - return furi_string_equal_str(device_type, MF_CLASSIC_PROTOCOL_NAME); + return furi_string_equal_str(device_type, "Mifare Classic"); } static void mf_classic_parse_block(FuriString* block_str, MfClassicData* data, uint8_t block_num) { @@ -154,7 +154,7 @@ bool mf_classic_load(MfClassicData* data, FlipperFormat* ff, uint32_t version) { if(!iso14443_3a_load(data->iso14443_3a_data, ff, version)) break; // Read Mifare Classic type - if(!flipper_format_read_string(ff, "MIFARE Classic type", temp_str)) break; + if(!flipper_format_read_string(ff, "Mifare Classic type", temp_str)) break; bool type_parsed = false; for(size_t i = 0; i < MfClassicTypeNum; i++) { if(furi_string_equal_str(temp_str, mf_classic_features[i].type_name)) { From 6103de175472fbf52a11722c4beffc12dad78558 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 12 Jan 2024 17:39:00 +0300 Subject: [PATCH 057/110] Rolled back all Mifare renamings in library files --- lib/nfc/helpers/nfc_data_generator.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index 0fb7062ff..21f062605 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -482,27 +482,27 @@ static void nfc_generate_mf_classic_4k_7b_uid(NfcDevice* nfc_device) { static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = { [NfcDataGeneratorTypeMfUltralight] = { - .name = "MIFARE Ultralight", + .name = "Mifare Ultralight", .handler = nfc_generate_mf_ul_orig, }, [NfcDataGeneratorTypeMfUltralightEV1_11] = { - .name = "MIFARE Ultralight EV1 11", + .name = "Mifare Ultralight EV1 11", .handler = nfc_generate_mf_ul_11, }, [NfcDataGeneratorTypeMfUltralightEV1_H11] = { - .name = "MIFARE Ultralight EV1 H11", + .name = "Mifare Ultralight EV1 H11", .handler = nfc_generate_mf_ul_h11, }, [NfcDataGeneratorTypeMfUltralightEV1_21] = { - .name = "MIFARE Ultralight EV1 21", + .name = "Mifare Ultralight EV1 21", .handler = nfc_generate_mf_ul_21, }, [NfcDataGeneratorTypeMfUltralightEV1_H21] = { - .name = "MIFARE Ultralight EV1 H21", + .name = "Mifare Ultralight EV1 H21", .handler = nfc_generate_mf_ul_h21, }, [NfcDataGeneratorTypeNTAG203] = @@ -547,27 +547,27 @@ static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = { }, [NfcDataGeneratorTypeMfClassicMini] = { - .name = "MIFARE Mini", + .name = "Mifare Mini", .handler = nfc_generate_mf_classic_mini, }, [NfcDataGeneratorTypeMfClassic1k_4b] = { - .name = "MIFARE Classic 1k 4byte UID", + .name = "Mifare Classic 1k 4byte UID", .handler = nfc_generate_mf_classic_1k_4b_uid, }, [NfcDataGeneratorTypeMfClassic1k_7b] = { - .name = "MIFARE Classic 1k 7byte UID", + .name = "Mifare Classic 1k 7byte UID", .handler = nfc_generate_mf_classic_1k_7b_uid, }, [NfcDataGeneratorTypeMfClassic4k_4b] = { - .name = "MIFARE Classic 4k 4byte UID", + .name = "Mifare Classic 4k 4byte UID", .handler = nfc_generate_mf_classic_4k_4b_uid, }, [NfcDataGeneratorTypeMfClassic4k_7b] = { - .name = "MIFARE Classic 4k 7byte UID", + .name = "Mifare Classic 4k 7byte UID", .handler = nfc_generate_mf_classic_4k_7b_uid, }, }; From 22aba527b7693aff444264da49700e12046719c0 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 12 Jan 2024 18:11:48 +0300 Subject: [PATCH 058/110] Revert "Change MIFARE name accroding to new requirements" This reverts commit cfb974dc1f5bff1d46a0483741b2b8f4726cdda3. --- applications/main/nfc/helpers/mf_classic_key_cache.c | 2 +- .../main/nfc/scenes/nfc_scene_extra_actions.c | 2 +- lib/nfc/protocols/mf_classic/mf_classic.c | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/applications/main/nfc/helpers/mf_classic_key_cache.c b/applications/main/nfc/helpers/mf_classic_key_cache.c index b28095110..5127e6452 100644 --- a/applications/main/nfc/helpers/mf_classic_key_cache.c +++ b/applications/main/nfc/helpers/mf_classic_key_cache.c @@ -58,7 +58,7 @@ bool mf_classic_key_cache_save(MfClassicKeyCache* instance, const MfClassicData* ff, mf_classic_key_cache_file_header, mf_classic_key_cache_file_version)) break; if(!flipper_format_write_string_cstr( - ff, "MIFARE Classic type", mf_classic_get_device_name(data, NfcDeviceNameTypeShort))) + ff, "Mifare Classic type", mf_classic_get_device_name(data, NfcDeviceNameTypeShort))) break; if(!flipper_format_write_hex_uint64(ff, "Key A map", &data->key_a_mask, 1)) break; if(!flipper_format_write_hex_uint64(ff, "Key B map", &data->key_b_mask, 1)) break; diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index d14f80b62..721919d2b 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -24,7 +24,7 @@ void nfc_scene_extra_actions_on_enter(void* context) { instance); submenu_add_item( submenu, - "MIFARE Classic Keys", + "Mifare Classic Keys", SubmenuIndexMfClassicKeys, nfc_scene_extra_actions_submenu_callback, instance); diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index e9dfb28f4..e68e8c718 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -21,21 +21,21 @@ static const MfClassicFeatures mf_classic_features[MfClassicTypeNum] = { { .sectors_total = 5, .blocks_total = 20, - .full_name = "MIFARE Classic Mini 0.3K", + .full_name = "Mifare Classic Mini 0.3K", .type_name = "MINI", }, [MfClassicType1k] = { .sectors_total = 16, .blocks_total = 64, - .full_name = "MIFARE Classic 1K", + .full_name = "Mifare Classic 1K", .type_name = "1K", }, [MfClassicType4k] = { .sectors_total = 40, .blocks_total = 256, - .full_name = "MIFARE Classic 4K", + .full_name = "Mifare Classic 4K", .type_name = "4K", }, }; @@ -261,15 +261,15 @@ bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff) { do { if(!iso14443_3a_save(data->iso14443_3a_data, ff)) break; - if(!flipper_format_write_comment_cstr(ff, "MIFARE Classic specific data")) break; + if(!flipper_format_write_comment_cstr(ff, "Mifare Classic specific data")) break; if(!flipper_format_write_string_cstr( - ff, "MIFARE Classic type", mf_classic_features[data->type].type_name)) + ff, "Mifare Classic type", mf_classic_features[data->type].type_name)) break; if(!flipper_format_write_uint32( ff, "Data format version", &mf_classic_data_format_version, 1)) break; if(!flipper_format_write_comment_cstr( - ff, "MIFARE Classic blocks, \'??\' means unknown data")) + ff, "Mifare Classic blocks, \'??\' means unknown data")) break; uint16_t blocks_total = mf_classic_get_total_block_num(data->type); From 321a56d934a9c911d25cf6e238ae5905915a8929 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Fri, 12 Jan 2024 23:33:53 +0300 Subject: [PATCH 059/110] Now Mifare word is changed only on the app level without changes to lib level --- .../protocol_support/mf_classic/mf_classic.c | 4 ++++ .../main/nfc/scenes/nfc_scene_extra_actions.c | 2 +- applications/main/nfc/scenes/nfc_scene_set_type.c | 14 ++++++++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index 97913b9d2..4f4668ea7 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -23,6 +23,8 @@ static void nfc_scene_info_on_enter_mf_classic(NfcApp* instance) { FuriString* temp_str = furi_string_alloc(); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + furi_string_replace(temp_str, "Mifare", "MIFARE"); + nfc_render_mf_classic_info(data, NfcProtocolFormatTypeFull, temp_str); widget_add_text_scroll_element( @@ -126,6 +128,8 @@ static void nfc_scene_read_success_on_enter_mf_classic(NfcApp* instance) { FuriString* temp_str = furi_string_alloc(); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + furi_string_replace(temp_str, "Mifare", "MIFARE"); + nfc_render_mf_classic_info(data, NfcProtocolFormatTypeShort, temp_str); widget_add_text_scroll_element( diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 721919d2b..d14f80b62 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -24,7 +24,7 @@ void nfc_scene_extra_actions_on_enter(void* context) { instance); submenu_add_item( submenu, - "Mifare Classic Keys", + "MIFARE Classic Keys", SubmenuIndexMfClassicKeys, nfc_scene_extra_actions_submenu_callback, instance); diff --git a/applications/main/nfc/scenes/nfc_scene_set_type.c b/applications/main/nfc/scenes/nfc_scene_set_type.c index e33660080..b5102f801 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_type.c +++ b/applications/main/nfc/scenes/nfc_scene_set_type.c @@ -32,10 +32,20 @@ void nfc_scene_set_type_on_enter(void* context) { nfc_protocol_support_common_submenu_callback, instance); + FuriString* str = furi_string_alloc(); for(size_t i = 0; i < NfcDataGeneratorTypeNum; i++) { - const char* name = nfc_data_generator_get_name(i); - submenu_add_item(submenu, name, i, nfc_protocol_support_common_submenu_callback, instance); + furi_string_cat_str(str, nfc_data_generator_get_name(i)); + furi_string_replace_str(str, "Mifare", "MIFARE"); + + submenu_add_item( + submenu, + furi_string_get_cstr(str), + i, + nfc_protocol_support_common_submenu_callback, + instance); + furi_string_reset(str); } + furi_string_free(str); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu); } From 08a5adf18ef95389f838879f5d07fcb73d2984b6 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Mon, 15 Jan 2024 03:53:03 +0000 Subject: [PATCH 060/110] Fix EMV reading 2 MasterCard were successfully read Issues: some VISA and Mastercard and all UnionPay can't be read TODO: currency, country, Application name TODO: Support multi application mode to read co-branded card. --- .../nfc/helpers/protocol_support/emv/emv.c | 8 +-- .../helpers/protocol_support/emv/emv_render.c | 53 +++++++++++++---- .../helpers/protocol_support/emv/emv_render.h | 10 +++- lib/nfc/protocols/emv/emv.h | 2 +- lib/nfc/protocols/emv/emv_poller.c | 13 ++-- lib/nfc/protocols/emv/emv_poller_i.c | 59 ++++++++++++------- 6 files changed, 99 insertions(+), 46 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv.c b/applications/main/nfc/helpers/protocol_support/emv/emv.c index 035f8d220..0b60bea6e 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv.c @@ -14,8 +14,8 @@ static void nfc_scene_info_on_enter_emv(NfcApp* instance) { const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); FuriString* temp_str = furi_string_alloc(); - furi_string_cat_printf( - temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + // furi_string_cat_printf( + // temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_emv_info(data, NfcProtocolFormatTypeFull, temp_str); widget_add_text_scroll_element( @@ -54,8 +54,8 @@ static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) { const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); FuriString* temp_str = furi_string_alloc(); - furi_string_cat_printf( - temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + // furi_string_cat_printf( + // temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_emv_info(data, NfcProtocolFormatTypeShort, temp_str); widget_add_text_scroll_element( diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c index 46cdc974f..ead426a15 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -3,15 +3,11 @@ #include "../iso14443_4a/iso14443_4a_render.h" void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str) { - nfc_render_iso14443_4a_brief(emv_get_base_data(data), str); - - nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str); nfc_render_emv_name(data->emv_application.name, str); + nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str); + nfc_render_emv_expired(&data->emv_application, str); - if(format_type != NfcProtocolFormatTypeFull) return; - - furi_string_cat(str, "\n\e#ISO14443-4 data"); - nfc_render_iso14443_4a_extra(emv_get_base_data(data), str); + if(format_type == NfcProtocolFormatTypeFull) nfc_render_emv_extra(data, str); } void nfc_render_emv_data(const EmvData* data, FuriString* str) { @@ -20,16 +16,49 @@ void nfc_render_emv_data(const EmvData* data, FuriString* str) { } void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str) { - for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%u", data[i]); + if(len == 0) return; + for(uint8_t i = 0; i < len; i += 2) { + furi_string_cat_printf(str, "%02X%02X ", data[i], data[i + 1]); + } furi_string_cat_printf(str, "\n"); } +void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str) { + if(apl->exp_month == 0) return; + furi_string_cat_printf(str, "Exp: %02X/%02X\n", apl->exp_month, apl->exp_year); +} + +void nfc_render_emv_currency(const EmvApplication* apl, FuriString* str) { + UNUSED(apl); + UNUSED(str); + // nfc/assets/currency_code.nfc +} + +void nfc_render_emv_country(const EmvApplication* apl, FuriString* str) { + UNUSED(apl); + UNUSED(str); + // nfc/assets/country_code.nfc +} + void nfc_render_emv_name(const char* data, FuriString* str) { - UNUSED(data); + if(strlen(data) == 0) return; + furi_string_cat_printf(str, "\e#"); + furi_string_cat(str, data); furi_string_cat_printf(str, "\n"); } -void nfc_render_emv_application(const EmvApplication* data, FuriString* str) { - UNUSED(data); +void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { + const uint8_t len = apl->aid_len; + if(len) { + furi_string_cat_printf(str, "AID: "); + for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]); + // nfc/assets/aid.nfc + } else { + furi_string_cat_printf(str, "No Pay Application found"); + } furi_string_cat_printf(str, "\n"); -} \ No newline at end of file +} + +void nfc_render_emv_extra(const EmvData* data, FuriString* str) { + nfc_render_emv_application(&data->emv_application, str); +} diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h index 16fc2e172..8fb31eaea 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h @@ -13,4 +13,12 @@ void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str) void nfc_render_emv_name(const char* data, FuriString* str); -void nfc_render_emv_application(const EmvApplication* data, FuriString* str); \ No newline at end of file +void nfc_render_emv_application(const EmvApplication* data, FuriString* str); + +void nfc_render_emv_extra(const EmvData* data, FuriString* str); + +void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str); + +void nfc_render_emv_country(const EmvApplication* apl, FuriString* str); + +void nfc_render_emv_currency(const EmvApplication* apl, FuriString* str); diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index 45318292b..913bdb0cb 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -41,7 +41,7 @@ typedef struct { bool app_started; char name[32]; bool name_found; - uint8_t pan[10]; + uint8_t pan[10]; // card_number uint8_t pan_len; uint8_t exp_month; uint8_t exp_year; diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c index 61ef1c30e..41ae8afba 100644 --- a/lib/nfc/protocols/emv/emv_poller.c +++ b/lib/nfc/protocols/emv/emv_poller.c @@ -71,7 +71,6 @@ static NfcCommand emv_poller_handler_select_ppse(EmvPoller* instance) { instance->state = EmvPollerStateSelectApplication; } else { FURI_LOG_E(TAG, "Failed to select PPSE"); - iso14443_4a_poller_halt(instance->iso14443_4a_poller); instance->state = EmvPollerStateReadFailed; } @@ -86,7 +85,6 @@ static NfcCommand emv_poller_handler_select_application(EmvPoller* instance) { instance->state = EmvPollerStateGetProcessingOptions; } else { FURI_LOG_E(TAG, "Failed to select application"); - iso14443_4a_poller_halt(instance->iso14443_4a_poller); instance->state = EmvPollerStateReadFailed; } @@ -98,10 +96,14 @@ static NfcCommand emv_poller_handler_get_processing_options(EmvPoller* instance) if(instance->error == EmvErrorNone) { FURI_LOG_D(TAG, "Get processing options success"); - instance->state = EmvPollerStateReadSuccess; + if(instance->data->emv_application.pan_len > 0) { + instance->state = EmvPollerStateReadSuccess; + } else { + FURI_LOG_D(TAG, "No AFL still. Fallback to bruteforce files"); + instance->state = EmvPollerStateReadFiles; + } } else { FURI_LOG_E(TAG, "Failed to get processing options"); - iso14443_4a_poller_halt(instance->iso14443_4a_poller); instance->state = EmvPollerStateReadFiles; } @@ -116,7 +118,6 @@ static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) { instance->state = EmvPollerStateReadSuccess; } else { FURI_LOG_E(TAG, "Failed to read files"); - iso14443_4a_poller_halt(instance->iso14443_4a_poller); instance->state = EmvPollerStateReadFailed; } @@ -133,7 +134,7 @@ static NfcCommand emv_poller_handler_read_fail(EmvPoller* instance) { } static NfcCommand emv_poller_handler_read_success(EmvPoller* instance) { - FURI_LOG_D(TAG, "Read success."); + FURI_LOG_D(TAG, "Read success"); iso14443_4a_poller_halt(instance->iso14443_4a_poller); instance->emv_event.type = EmvPollerEventTypeReadSuccess; NfcCommand command = instance->callback(instance->general_event, instance->context); diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index da8503744..739747296 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -183,6 +183,7 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio break; } case EMV_TAG_TRACK_2_EQUIV: { + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2_EQUIV %x", tag); // 0xD0 delimits PAN from expiry (YYMM) for(int x = 1; x < tlen; x++) { if(buff[i + x + 1] > 0xD0) { @@ -194,41 +195,45 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio } } - // Convert 4-bit to ASCII representation - char track_2_equiv[41]; - uint8_t track_2_equiv_len = 0; - for(int x = 0; x < tlen; x++) { - char top = (buff[i + x] >> 4) + '0'; - char bottom = (buff[i + x] & 0x0F) + '0'; - track_2_equiv[x * 2] = top; - track_2_equiv_len++; - if(top == '?') break; - track_2_equiv[x * 2 + 1] = bottom; - track_2_equiv_len++; - if(bottom == '?') break; - } - track_2_equiv[track_2_equiv_len] = '\0'; + // // Convert 4-bit to ASCII representation + // char track_2_equiv[41]; + // uint8_t track_2_equiv_len = 0; + // for(int x = 0; x < tlen; x++) { + // char top = (buff[i + x] >> 4) + '0'; + // char bottom = (buff[i + x] & 0x0F) + '0'; + // track_2_equiv[x * 2] = top; + // track_2_equiv_len++; + // if(top == '?') break; + // track_2_equiv[x * 2 + 1] = bottom; + // track_2_equiv_len++; + // if(bottom == '?') break; + // } + // track_2_equiv[track_2_equiv_len] = '\0'; + // FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2_EQUIV %x : %s", tag, track_2_equiv); success = true; - FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2_EQUIV %x : %s", tag, track_2_equiv); break; } case EMV_TAG_PAN: memcpy(app->pan, &buff[i], tlen); app->pan_len = tlen; success = true; + FURI_LOG_T(TAG, "found EMV_TAG_PAN %x", tag); break; case EMV_TAG_EXP_DATE: app->exp_year = buff[i]; app->exp_month = buff[i + 1]; success = true; + FURI_LOG_T(TAG, "found EMV_TAG_EXP_DATE %x", tag); break; case EMV_TAG_CURRENCY_CODE: app->currency_code = (buff[i] << 8 | buff[i + 1]); success = true; + FURI_LOG_T(TAG, "found EMV_TAG_CURRENCY_CODE %x", tag); break; case EMV_TAG_COUNTRY_CODE: app->country_code = (buff[i] << 8 | buff[i + 1]); success = true; + FURI_LOG_T(TAG, "found EMV_TAG_COUNTRY_CODE %x", tag); break; } } @@ -413,6 +418,7 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re emv_trace(instance, "SFI record:"); if(iso14443_4a_error != Iso14443_4aErrorNone) { + FURI_LOG_E(TAG, "Failed to read SFI %d record %d", sfi, record_num); error = emv_process_error(iso14443_4a_error); break; } @@ -423,8 +429,9 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re buff, bit_buffer_get_size_bytes(instance->rx_buffer), &instance->data->emv_application)) { - error = EmvErrorProtocol; - FURI_LOG_E(TAG, "Failed to read SFI record %d", record_num); + // It's ok while bruteforcing + //error = EmvErrorProtocol; + FURI_LOG_T(TAG, "Failed to parse SFI %d record %d", sfi, record_num); } } while(false); @@ -449,8 +456,12 @@ EmvError emv_poller_read_files(EmvPoller* instance) { uint8_t record_end = afl->data[i + 2]; // Iterate through all records in file for(uint8_t record = record_start; record <= record_end; ++record) { - error |= emv_poller_read_sfi_record(instance, sfi, record); + error = emv_poller_read_sfi_record(instance, sfi, record); + if(error != EmvErrorNone) break; + if(instance->data->emv_application.pan_len != 0) + return EmvErrorNone; // Card number fetched } + error = EmvErrorProtocol; } return error; @@ -462,15 +473,19 @@ EmvError emv_poller_read(EmvPoller* instance) { memset(&instance->data->emv_application, 0, sizeof(EmvApplication)); do { - error |= emv_poller_select_ppse(instance); + error = emv_poller_select_ppse(instance); if(error != EmvErrorNone) break; - error |= emv_poller_select_application(instance); + error = emv_poller_select_application(instance); if(error != EmvErrorNone) break; - if(emv_poller_get_processing_options(instance) != EmvErrorNone) + error = emv_poller_get_processing_options(instance); + if(error != EmvErrorNone) break; + + if(instance->data->emv_application.pan_len == 0) { error = emv_poller_read_files(instance); - + if(error != EmvErrorNone) break; + } } while(false); return error; From 957a89f2b38a7dde3cd84f29c533fa9245fd0588 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Mon, 15 Jan 2024 19:38:28 +0300 Subject: [PATCH 061/110] Filename or "Unsaved + CardType" is now showed for saved cards during emulation --- .../helpers/protocol_support/nfc_protocol_support.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index ad7f5a0d1..b88531138 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -582,8 +582,14 @@ static void nfc_protocol_support_scene_emulate_on_enter(NfcApp* instance) { } else { widget_add_string_element(widget, 90, 13, AlignCenter, AlignTop, FontPrimary, "Emulating"); - furi_string_set( - temp_str, nfc_device_get_name(instance->nfc_device, NfcDeviceNameTypeFull)); + if(!furi_string_empty(instance->file_name)) { + furi_string_set(temp_str, instance->file_name); + } else { + furi_string_printf( + temp_str, + "Unsaved\n%s", + nfc_device_get_name(instance->nfc_device, NfcDeviceNameTypeFull)); + } } widget_add_text_box_element( From be15c5ff4a45c6bc5314b76d1eb7fdae05221de0 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Mon, 15 Jan 2024 20:02:08 +0300 Subject: [PATCH 062/110] Headers added to Write scenes --- .../main/nfc/scenes/nfc_scene_mf_classic_write_initial.c | 3 ++- applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial.c index 79f1def1d..da576a276 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial.c @@ -65,8 +65,9 @@ static void nfc_scene_mf_classic_write_initial_setup_view(NfcApp* instance) { scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicWriteInitial); if(state == NfcSceneMfClassicWriteInitialStateCardSearch) { + popup_set_header(instance->popup, "Writing", 95, 20, AlignCenter, AlignCenter); popup_set_text( - instance->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); + instance->popup, "Apply the initial\ncard only", 95, 38, AlignCenter, AlignCenter); popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); } else { popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c index b3c1beef5..157d6ce1b 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c @@ -46,8 +46,9 @@ static void nfc_scene_mf_ultralight_write_setup_view(NfcApp* instance) { scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfUltralightWrite); if(state == NfcSceneMfUltralightWriteStateCardSearch) { + popup_set_header(instance->popup, "Writing", 95, 20, AlignCenter, AlignCenter); popup_set_text( - instance->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); + instance->popup, "Apply the initial\ncard only", 95, 38, AlignCenter, AlignCenter); popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); } else { popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter); From ba6b56445d1f73a1269441896bc5048eb0de6acc Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Mon, 15 Jan 2024 20:29:21 +0300 Subject: [PATCH 063/110] Reordered menu items accrding to new spec --- .../protocol_support/nfc_protocol_support.c | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index b88531138..c87ee613f 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -391,12 +391,15 @@ static void nfc_protocol_support_scene_saved_menu_on_enter(NfcApp* instance) { nfc_protocol_support[protocol]->scene_saved_menu.on_enter(instance); // Trailer submenu items - submenu_add_item( - submenu, - "Info", - SubmenuIndexCommonInfo, - nfc_protocol_support_common_submenu_callback, - instance); + if(nfc_has_shadow_file(instance)) { + submenu_add_item( + submenu, + "Restore to Original State", + SubmenuIndexCommonRestore, + nfc_protocol_support_common_submenu_callback, + instance); + } + submenu_add_item( submenu, "Rename", @@ -409,15 +412,12 @@ static void nfc_protocol_support_scene_saved_menu_on_enter(NfcApp* instance) { SubmenuIndexCommonDelete, nfc_protocol_support_common_submenu_callback, instance); - - if(nfc_has_shadow_file(instance)) { - submenu_add_item( - submenu, - "Restore Data Changes", - SubmenuIndexCommonRestore, - nfc_protocol_support_common_submenu_callback, - instance); - } + submenu_add_item( + submenu, + "Info", + SubmenuIndexCommonInfo, + nfc_protocol_support_common_submenu_callback, + instance); submenu_set_selected_item( instance->submenu, From 4b7b0ad6b9ed84eb3890720c77be96ee58647b7f Mon Sep 17 00:00:00 2001 From: Methodius Date: Tue, 16 Jan 2024 02:43:17 +0900 Subject: [PATCH 064/110] EMV parser added --- applications/main/nfc/application.fam | 9 + .../main/nfc/plugins/supported_cards/emv.c | 923 ++++++++++++++++++ lib/nfc/protocols/emv/emv.h | 1 - lib/nfc/protocols/emv/emv_poller.h | 2 - lib/nfc/protocols/emv/emv_poller_i.c | 28 - targets/f7/api_symbols.csv | 3 +- 6 files changed, 933 insertions(+), 33 deletions(-) create mode 100644 applications/main/nfc/plugins/supported_cards/emv.c diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index d74447844..0ed7a6241 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -182,6 +182,15 @@ App( sources=["plugins/supported_cards/ndef.c"], ) +App( + appid="emv_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="emv_plugin_ep", + targets=["f7"], + requires=["nfc"], + sources=["plugins/supported_cards/emv.c"], +) + App( appid="nfc_start", targets=["f7"], diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c new file mode 100644 index 000000000..fabf721ae --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -0,0 +1,923 @@ +/* + * Parser for EMV cards. + * + * Copyright 2023 Leptoptilos + * + * 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 . + */ +#include "core/string.h" +#include "furi_hal_rtc.h" +#include "nfc_supported_card_plugin.h" + +#include "protocols/emv/emv.h" +#include "protocols/nfc_protocol.h" +#include + +#include +#include + +#define TAG "EMV" + +char* get_country_name(uint16_t country_code) { + switch(country_code) { + case 0x0004: + return "AFG"; + case 0x0008: + return "ALB"; + case 0x0010: + return "ATA"; + case 0x0012: + return "DZA"; + case 0x0016: + return "ASM"; + case 0x0020: + return "AND"; + case 0x0024: + return "AGO"; + case 0x0028: + return "ATG"; + case 0x0031: + return "AZE"; + case 0x0032: + return "ARG"; + case 0x0036: + return "AUS"; + case 0x0040: + return "AUT"; + case 0x0044: + return "BHS"; + case 0x0048: + return "BHR"; + case 0x0050: + return "BGD"; + case 0x0051: + return "ARM"; + case 0x0052: + return "BRB"; + case 0x0056: + return "BEL"; + case 0x0060: + return "BMU"; + case 0x0064: + return "BTN"; + case 0x0068: + return "BOL"; + case 0x0070: + return "BIH"; + case 0x0072: + return "BWA"; + case 0x0074: + return "BVT"; + case 0x0076: + return "BRA"; + case 0x0084: + return "BLZ"; + case 0x0086: + return "IOT"; + case 0x0090: + return "SLB"; + case 0x0092: + return "VGB"; + case 0x0096: + return "BRN"; + case 0x0100: + return "BGR"; + case 0x0104: + return "MMR"; + case 0x0108: + return "BDI"; + case 0x0112: + return "BLR"; + case 0x0116: + return "KHM"; + case 0x0120: + return "CMR"; + case 0x0124: + return "CAN"; + case 0x0132: + return "CPV"; + case 0x0136: + return "CYM"; + case 0x0140: + return "CAF"; + case 0x0144: + return "LKA"; + case 0x0148: + return "TCD"; + case 0x0152: + return "CHL"; + case 0x0156: + return "CHN"; + case 0x0158: + return "TWN"; + case 0x0162: + return "CXR"; + case 0x0166: + return "CCK"; + case 0x0170: + return "COL"; + case 0x0174: + return "COM"; + case 0x0175: + return "MYT"; + case 0x0178: + return "COG"; + case 0x0180: + return "COD"; + case 0x0184: + return "COK"; + case 0x0188: + return "CRI"; + case 0x0191: + return "HRV"; + case 0x0192: + return "CUB"; + case 0x0196: + return "CYP"; + case 0x0203: + return "CZE"; + case 0x0204: + return "BEN"; + case 0x0208: + return "DNK"; + case 0x0212: + return "DMA"; + case 0x0214: + return "DOM"; + case 0x0218: + return "ECU"; + case 0x0222: + return "SLV"; + case 0x0226: + return "GNQ"; + case 0x0231: + return "ETH"; + case 0x0232: + return "ERI"; + case 0x0233: + return "EST"; + case 0x0234: + return "FRO"; + case 0x0238: + return "FLK"; + case 0x0239: + return "SGS"; + case 0x0242: + return "FJI"; + case 0x0246: + return "FIN"; + case 0x0248: + return "ALA"; + case 0x0250: + return "FRA"; + case 0x0254: + return "GUF"; + case 0x0258: + return "PYF"; + case 0x0260: + return "ATF"; + case 0x0262: + return "DJI"; + case 0x0266: + return "GAB"; + case 0x0268: + return "GEO"; + case 0x0270: + return "GMB"; + case 0x0275: + return "PSE"; + case 0x0276: + return "DEU"; + case 0x0288: + return "GHA"; + case 0x0292: + return "GIB"; + case 0x0296: + return "KIR"; + case 0x0300: + return "GRC"; + case 0x0304: + return "GRL"; + case 0x0308: + return "GRD"; + case 0x0312: + return "GLP"; + case 0x0316: + return "GUM"; + case 0x0320: + return "GTM"; + case 0x0324: + return "GIN"; + case 0x0328: + return "GUY"; + case 0x0332: + return "HTI"; + case 0x0334: + return "HMD"; + case 0x0336: + return "VAT"; + case 0x0340: + return "HND"; + case 0x0344: + return "HKG"; + case 0x0348: + return "HUN"; + case 0x0352: + return "ISL"; + case 0x0356: + return "IND"; + case 0x0360: + return "IDN"; + case 0x0364: + return "IRN"; + case 0x0368: + return "IRQ"; + case 0x0372: + return "IRL"; + case 0x0376: + return "ISR"; + case 0x0380: + return "ITA"; + case 0x0384: + return "CIV"; + case 0x0388: + return "JAM"; + case 0x0392: + return "JPN"; + case 0x0398: + return "KAZ"; + case 0x0400: + return "JOR"; + case 0x0404: + return "KEN"; + case 0x0408: + return "PRK"; + case 0x0410: + return "KOR"; + case 0x0414: + return "KWT"; + case 0x0417: + return "KGZ"; + case 0x0418: + return "LAO"; + case 0x0422: + return "LBN"; + case 0x0426: + return "LSO"; + case 0x0428: + return "LVA"; + case 0x0430: + return "LBR"; + case 0x0434: + return "LBY"; + case 0x0438: + return "LIE"; + case 0x0440: + return "LTU"; + case 0x0442: + return "LUX"; + case 0x0446: + return "MAC"; + case 0x0450: + return "MDG"; + case 0x0454: + return "MWI"; + case 0x0458: + return "MYS"; + case 0x0462: + return "MDV"; + case 0x0466: + return "MLI"; + case 0x0470: + return "MLT"; + case 0x0474: + return "MTQ"; + case 0x0478: + return "MRT"; + case 0x0480: + return "MUS"; + case 0x0484: + return "MEX"; + case 0x0492: + return "MCO"; + case 0x0496: + return "MNG"; + case 0x0498: + return "MDA"; + case 0x0499: + return "MNE"; + case 0x0500: + return "MSR"; + case 0x0504: + return "MAR"; + case 0x0508: + return "MOZ"; + case 0x0512: + return "OMN"; + case 0x0516: + return "NAM"; + case 0x0520: + return "NRU"; + case 0x0524: + return "NPL"; + case 0x0528: + return "NLD"; + case 0x0531: + return "CUW"; + case 0x0533: + return "ABW"; + case 0x0534: + return "SXM"; + case 0x0535: + return "BES"; + case 0x0540: + return "NCL"; + case 0x0548: + return "VUT"; + case 0x0554: + return "NZL"; + case 0x0558: + return "NIC"; + case 0x0562: + return "NER"; + case 0x0566: + return "NGA"; + case 0x0570: + return "NIU"; + case 0x0574: + return "NFK"; + case 0x0578: + return "NOR"; + case 0x0580: + return "MNP"; + case 0x0581: + return "UMI"; + case 0x0583: + return "FSM"; + case 0x0584: + return "MHL"; + case 0x0585: + return "PLW"; + case 0x0586: + return "PAK"; + case 0x0591: + return "PAN"; + case 0x0598: + return "PNG"; + case 0x0600: + return "PRY"; + case 0x0604: + return "PER"; + case 0x0608: + return "PHL"; + case 0x0612: + return "PCN"; + case 0x0616: + return "POL"; + case 0x0620: + return "PRT"; + case 0x0624: + return "GNB"; + case 0x0626: + return "TLS"; + case 0x0630: + return "PRI"; + case 0x0634: + return "QAT"; + case 0x0638: + return "REU"; + case 0x0642: + return "ROU"; + case 0x0643: + return "RUS"; + case 0x0646: + return "RWA"; + case 0x0652: + return "BLM"; + case 0x0654: + return "SHN"; + case 0x0659: + return "KNA"; + case 0x0660: + return "AIA"; + case 0x0662: + return "LCA"; + case 0x0663: + return "MAF"; + case 0x0666: + return "SPM"; + case 0x0670: + return "VCT"; + case 0x0674: + return "SMR"; + case 0x0678: + return "STP"; + case 0x0682: + return "SAU"; + case 0x0686: + return "SEN"; + case 0x0688: + return "SRB"; + case 0x0690: + return "SYC"; + case 0x0694: + return "SLE"; + case 0x0702: + return "SGP"; + case 0x0703: + return "SVK"; + case 0x0704: + return "VNM"; + case 0x0705: + return "SVN"; + case 0x0706: + return "SOM"; + case 0x0710: + return "ZAF"; + case 0x0716: + return "ZWE"; + case 0x0724: + return "ESP"; + case 0x0728: + return "SSD"; + case 0x0729: + return "SDN"; + case 0x0732: + return "ESH"; + case 0x0740: + return "SUR"; + case 0x0744: + return "SJM"; + case 0x0748: + return "SWZ"; + case 0x0752: + return "SWE"; + case 0x0756: + return "CHE"; + case 0x0760: + return "SYR"; + case 0x0762: + return "TJK"; + case 0x0764: + return "THA"; + case 0x0768: + return "TGO"; + case 0x0772: + return "TKL"; + case 0x0776: + return "TON"; + case 0x0780: + return "TTO"; + case 0x0784: + return "ARE"; + case 0x0788: + return "TUN"; + case 0x0792: + return "TUR"; + case 0x0795: + return "TKM"; + case 0x0796: + return "TCA"; + case 0x0798: + return "TUV"; + case 0x0800: + return "UGA"; + case 0x0804: + return "UKR"; + case 0x0807: + return "MKD"; + case 0x0818: + return "EGY"; + case 0x0826: + return "GBR"; + case 0x0831: + return "GGY"; + case 0x0832: + return "JEY"; + case 0x0833: + return "IMN"; + case 0x0834: + return "TZA"; + case 0x0840: + return "USA"; + case 0x0850: + return "VIR"; + case 0x0854: + return "BFA"; + case 0x0858: + return "URY"; + case 0x0860: + return "UZB"; + case 0x0862: + return "VEN"; + case 0x0876: + return "WLF"; + case 0x0882: + return "WSM"; + case 0x0887: + return "YEM"; + case 0x0894: + return "ZMB"; + default: + return "UNKNOWN"; + } +} + +char* get_currency_name(uint16_t currency_code) { + switch(currency_code) { + case 0x0997: + return "USN"; + case 0x0994: + return "XSU"; + case 0x0990: + return "CLF"; + case 0x0986: + return "BRL"; + case 0x0985: + return "PLN"; + case 0x0984: + return "BOV"; + case 0x0981: + return "GEL"; + case 0x0980: + return "UAH"; + case 0x0979: + return "MXV"; + case 0x0978: + return "EUR"; + case 0x0977: + return "BAM"; + case 0x0976: + return "CDF"; + case 0x0975: + return "BGN"; + case 0x0973: + return "AOA"; + case 0x0972: + return "TJS"; + case 0x0971: + return "AFN"; + case 0x0970: + return "COU"; + case 0x0969: + return "MGA"; + case 0x0968: + return "SRD"; + case 0x0967: + return "ZMW"; + case 0x0965: + return "XUA"; + case 0x0960: + return "XDR"; + case 0x0953: + return "XPF"; + case 0x0952: + return "XOF"; + case 0x0951: + return "XCD"; + case 0x0950: + return "XAF"; + case 0x0949: + return "TRY"; + case 0x0948: + return "CHW"; + case 0x0947: + return "CHE"; + case 0x0946: + return "RON"; + case 0x0944: + return "AZN"; + case 0x0943: + return "MZN"; + case 0x0941: + return "RSD"; + case 0x0940: + return "UYI"; + case 0x0938: + return "SDG"; + case 0x0937: + return "VEF"; + case 0x0936: + return "GHS"; + case 0x0934: + return "TMT"; + case 0x0933: + return "BYN"; + case 0x0932: + return "ZWL"; + case 0x0931: + return "CUC"; + case 0x0930: + return "STN"; + case 0x0929: + return "MRU"; + case 0x0901: + return "TWD"; + case 0x0886: + return "YER"; + case 0x0882: + return "WST"; + case 0x0860: + return "UZS"; + case 0x0858: + return "UYU"; + case 0x0840: + return "USD"; + case 0x0834: + return "TZS"; + case 0x0826: + return "GBP"; + case 0x0818: + return "EGP"; + case 0x0807: + return "MKD"; + case 0x0800: + return "UGX"; + case 0x0788: + return "TND"; + case 0x0784: + return "AED"; + case 0x0780: + return "TTD"; + case 0x0776: + return "TOP"; + case 0x0764: + return "THB"; + case 0x0760: + return "SYP"; + case 0x0756: + return "CHF"; + case 0x0752: + return "SEK"; + case 0x0748: + return "SZL"; + case 0x0728: + return "SSP"; + case 0x0710: + return "ZAR"; + case 0x0706: + return "SOS"; + case 0x0704: + return "VND"; + case 0x0702: + return "SGD"; + case 0x0694: + return "SLL"; + case 0x0690: + return "SCR"; + case 0x0682: + return "SAR"; + case 0x0654: + return "SHP"; + case 0x0646: + return "RWF"; + case 0x0643: + return "RUB"; + case 0x0634: + return "QAR"; + case 0x0608: + return "PHP"; + case 0x0604: + return "PEN"; + case 0x0600: + return "PYG"; + case 0x0598: + return "PGK"; + case 0x0590: + return "PAB"; + case 0x0586: + return "PKR"; + case 0x0578: + return "NOK"; + case 0x0566: + return "NGN"; + case 0x0558: + return "NIO"; + case 0x0554: + return "NZD"; + case 0x0548: + return "VUV"; + case 0x0533: + return "AWG"; + case 0x0532: + return "ANG"; + case 0x0524: + return "NPR"; + case 0x0516: + return "NAD"; + case 0x0512: + return "OMR"; + case 0x0504: + return "MAD"; + case 0x0498: + return "MDL"; + case 0x0496: + return "MNT"; + case 0x0484: + return "MXN"; + case 0x0480: + return "MUR"; + case 0x0462: + return "MVR"; + case 0x0458: + return "MYR"; + case 0x0454: + return "MWK"; + case 0x0446: + return "MOP"; + case 0x0434: + return "LYD"; + case 0x0430: + return "LRD"; + case 0x0426: + return "LSL"; + case 0x0422: + return "LBP"; + case 0x0418: + return "LAK"; + case 0x0417: + return "KGS"; + case 0x0414: + return "KWD"; + case 0x0410: + return "KRW"; + case 0x0408: + return "KPW"; + case 0x0404: + return "KES"; + case 0x0400: + return "JOD"; + case 0x0398: + return "KZT"; + case 0x0392: + return "JPY"; + case 0x0388: + return "JMD"; + case 0x0376: + return "ILS"; + case 0x0368: + return "IQD"; + case 0x0364: + return "IRR"; + case 0x0360: + return "IDR"; + case 0x0356: + return "INR"; + case 0x0352: + return "ISK"; + case 0x0348: + return "HUF"; + case 0x0344: + return "HKD"; + case 0x0340: + return "HNL"; + case 0x0332: + return "HTG"; + case 0x0328: + return "GYD"; + case 0x0324: + return "GNF"; + case 0x0320: + return "GTQ"; + case 0x0292: + return "GIP"; + case 0x0270: + return "GMD"; + case 0x0262: + return "DJF"; + case 0x0242: + return "FJD"; + case 0x0238: + return "FKP"; + case 0x0232: + return "ERN"; + case 0x0230: + return "ETB"; + case 0x0222: + return "SVC"; + case 0x0214: + return "DOP"; + case 0x0208: + return "DKK"; + case 0x0203: + return "CZK"; + case 0x0192: + return "CUP"; + case 0x0191: + return "HRK"; + case 0x0188: + return "CRC"; + case 0x0174: + return "KMF"; + case 0x0170: + return "COP"; + case 0x0156: + return "CNY"; + case 0x0152: + return "CLP"; + case 0x0144: + return "LKR"; + case 0x0136: + return "KYD"; + case 0x0132: + return "CVE"; + case 0x0124: + return "CAD"; + case 0x0116: + return "KHR"; + case 0x0108: + return "BIF"; + case 0x0104: + return "MMK"; + case 0x0096: + return "BND"; + case 0x0090: + return "SBD"; + case 0x0084: + return "BZD"; + case 0x0072: + return "BWP"; + case 0x0068: + return "BOB"; + case 0x0064: + return "BTN"; + case 0x0060: + return "BMD"; + case 0x0052: + return "BBD"; + case 0x0051: + return "AMD"; + case 0x0050: + return "BDT"; + case 0x0048: + return "BHD"; + case 0x0044: + return "BSD"; + case 0x0036: + return "AUD"; + case 0x0032: + return "ARS"; + case 0x0012: + return "DZD"; + case 0x0008: + return "ALL"; + default: + return "UNKNOWN"; + } +} + +static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + bool parsed = false; + + const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); + const EmvApplication app = data->emv_application; + + do { + furi_string_cat_printf(parsed_data, "\e#AID:\n"); + for(uint8_t i = 0; i < app.aid_len; i++) + furi_string_cat_printf(parsed_data, "%02X ", app.aid[i]); + + furi_string_cat_printf(parsed_data, "\nCountry: %s", get_country_name(app.country_code)); + + furi_string_cat_printf( + parsed_data, "\nCurrency: %s", get_currency_name(app.currency_code)); + + if(app.name_found) furi_string_cat_printf(parsed_data, "\nName: %s", app.name); + + parsed = true; + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin emv_plugin = { + .protocol = NfcProtocolEmv, + .verify = NULL, + .read = NULL, + .parse = emv_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor emv_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &emv_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* emv_plugin_ep() { + return &emv_plugin_descriptor; +} \ No newline at end of file diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index 913bdb0cb..a10450b7e 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -38,7 +38,6 @@ typedef struct { uint8_t priority; uint8_t aid[16]; uint8_t aid_len; - bool app_started; char name[32]; bool name_found; uint8_t pan[10]; // card_number diff --git a/lib/nfc/protocols/emv/emv_poller.h b/lib/nfc/protocols/emv/emv_poller.h index 8c053ede4..36f27578a 100644 --- a/lib/nfc/protocols/emv/emv_poller.h +++ b/lib/nfc/protocols/emv/emv_poller.h @@ -48,8 +48,6 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re EmvError emv_poller_read_files(EmvPoller* instance); -EmvError emv_poller_read(EmvPoller* instance); - #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 739747296..9494ca199 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -289,9 +289,6 @@ EmvError emv_poller_select_ppse(EmvPoller* instance) { EmvError emv_poller_select_application(EmvPoller* instance) { EmvError error = EmvErrorNone; - // DELETE IT??????????????????????????????????????????????????????????????????????????????????????? - instance->data->emv_application.app_started = false; - const uint8_t emv_select_header[] = { 0x00, 0xA4, // SELECT application @@ -338,7 +335,6 @@ EmvError emv_poller_select_application(EmvPoller* instance) { break; } - instance->data->emv_application.app_started = true; } while(false); return error; @@ -464,29 +460,5 @@ EmvError emv_poller_read_files(EmvPoller* instance) { error = EmvErrorProtocol; } - return error; -} - -EmvError emv_poller_read(EmvPoller* instance) { - furi_assert(instance); - EmvError error = EmvErrorNone; - - memset(&instance->data->emv_application, 0, sizeof(EmvApplication)); - do { - error = emv_poller_select_ppse(instance); - if(error != EmvErrorNone) break; - - error = emv_poller_select_application(instance); - if(error != EmvErrorNone) break; - - error = emv_poller_get_processing_options(instance); - if(error != EmvErrorNone) break; - - if(instance->data->emv_application.pan_len == 0) { - error = emv_poller_read_files(instance); - if(error != EmvErrorNone) break; - } - } while(false); - return error; } \ No newline at end of file diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 5272c0945..95b0bd5cd 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,50.2,, +Version,+,51.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -888,7 +888,6 @@ Function,+,emv_get_uid,const uint8_t*,"const EmvData*, size_t*" Function,+,emv_is_equal,_Bool,"const EmvData*, const EmvData*" Function,+,emv_load,_Bool,"EmvData*, FlipperFormat*, uint32_t" Function,+,emv_poller_get_processing_options,EmvError,EmvPoller* -Function,+,emv_poller_read,EmvError,EmvPoller* Function,+,emv_poller_read_files,EmvError,EmvPoller* Function,+,emv_poller_read_sfi_record,EmvError,"EmvPoller*, uint8_t, uint8_t" Function,+,emv_poller_select_application,EmvError,EmvPoller* From bae0baa42f7281dd41335ff514edb7e8d476b796 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 16 Jan 2024 22:24:54 +0300 Subject: [PATCH 065/110] Filename will be printed for saved tag in info scene --- .../main/nfc/helpers/protocol_support/felica/felica.c | 1 + .../helpers/protocol_support/iso14443_3a/iso14443_3a.c | 2 ++ .../helpers/protocol_support/iso14443_3b/iso14443_3b.c | 1 + .../helpers/protocol_support/iso14443_4a/iso14443_4a.c | 1 + .../helpers/protocol_support/iso14443_4b/iso14443_4b.c | 1 + .../nfc/helpers/protocol_support/iso15693_3/iso15693_3.c | 1 + .../nfc/helpers/protocol_support/mf_classic/mf_classic.c | 1 + .../nfc/helpers/protocol_support/mf_desfire/mf_desfire.c | 1 + .../protocol_support/mf_ultralight/mf_ultralight.c | 2 ++ .../main/nfc/helpers/protocol_support/slix/slix.c | 1 + .../main/nfc/helpers/protocol_support/st25tb/st25tb.c | 1 + applications/main/nfc/nfc_app.c | 9 +++++++++ applications/main/nfc/nfc_app_i.h | 2 ++ 13 files changed, 24 insertions(+) diff --git a/applications/main/nfc/helpers/protocol_support/felica/felica.c b/applications/main/nfc/helpers/protocol_support/felica/felica.c index f9c849121..6e7aa2d8a 100644 --- a/applications/main/nfc/helpers/protocol_support/felica/felica.c +++ b/applications/main/nfc/helpers/protocol_support/felica/felica.c @@ -13,6 +13,7 @@ static void nfc_scene_info_on_enter_felica(NfcApp* instance) { const FelicaData* data = nfc_device_get_data(device, NfcProtocolFelica); FuriString* temp_str = furi_string_alloc(); + nfc_append_filename_string_when_present(instance, temp_str); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_felica_info(data, NfcProtocolFormatTypeFull, temp_str); diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c index c0d502d03..05db74a4e 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c @@ -13,6 +13,8 @@ static void nfc_scene_info_on_enter_iso14443_3a(NfcApp* instance) { const Iso14443_3aData* data = nfc_device_get_data(device, NfcProtocolIso14443_3a); FuriString* temp_str = furi_string_alloc(); + nfc_append_filename_string_when_present(instance, temp_str); + furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_iso14443_3a_info(data, NfcProtocolFormatTypeFull, temp_str); diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c index fee231846..a71a65753 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c @@ -13,6 +13,7 @@ static void nfc_scene_info_on_enter_iso14443_3b(NfcApp* instance) { const Iso14443_3bData* data = nfc_device_get_data(device, NfcProtocolIso14443_3b); FuriString* temp_str = furi_string_alloc(); + nfc_append_filename_string_when_present(instance, temp_str); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_iso14443_3b_info(data, NfcProtocolFormatTypeFull, temp_str); diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c index 0a3a592e1..5bd38975d 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c @@ -14,6 +14,7 @@ static void nfc_scene_info_on_enter_iso14443_4a(NfcApp* instance) { const Iso14443_4aData* data = nfc_device_get_data(device, NfcProtocolIso14443_4a); FuriString* temp_str = furi_string_alloc(); + nfc_append_filename_string_when_present(instance, temp_str); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_iso14443_4a_info(data, NfcProtocolFormatTypeFull, temp_str); diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4b/iso14443_4b.c b/applications/main/nfc/helpers/protocol_support/iso14443_4b/iso14443_4b.c index a0c70a22e..ee49f2a42 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_4b/iso14443_4b.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4b/iso14443_4b.c @@ -14,6 +14,7 @@ static void nfc_scene_info_on_enter_iso14443_4b(NfcApp* instance) { const Iso14443_4bData* data = nfc_device_get_data(device, NfcProtocolIso14443_4b); FuriString* temp_str = furi_string_alloc(); + nfc_append_filename_string_when_present(instance, temp_str); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_iso14443_4b_info(data, NfcProtocolFormatTypeFull, temp_str); diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c index 7f861a032..b0110bc29 100644 --- a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c @@ -14,6 +14,7 @@ static void nfc_scene_info_on_enter_iso15693_3(NfcApp* instance) { const Iso15693_3Data* data = nfc_device_get_data(device, NfcProtocolIso15693_3); FuriString* temp_str = furi_string_alloc(); + nfc_append_filename_string_when_present(instance, temp_str); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_iso15693_3_info(data, NfcProtocolFormatTypeFull, temp_str); diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index 7feeccf22..6cba77250 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -21,6 +21,7 @@ static void nfc_scene_info_on_enter_mf_classic(NfcApp* instance) { const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); FuriString* temp_str = furi_string_alloc(); + nfc_append_filename_string_when_present(instance, temp_str); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); furi_string_replace(temp_str, "Mifare", "MIFARE"); diff --git a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c index bc05c2a4c..9d24a74ec 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c @@ -14,6 +14,7 @@ static void nfc_scene_info_on_enter_mf_desfire(NfcApp* instance) { const MfDesfireData* data = nfc_device_get_data(device, NfcProtocolMfDesfire); FuriString* temp_str = furi_string_alloc(); + nfc_append_filename_string_when_present(instance, temp_str); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_mf_desfire_info(data, NfcProtocolFormatTypeFull, temp_str); diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 4a8d4d744..3efa032bc 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -20,6 +20,8 @@ static void nfc_scene_info_on_enter_mf_ultralight(NfcApp* instance) { const MfUltralightData* data = nfc_device_get_data(device, NfcProtocolMfUltralight); FuriString* temp_str = furi_string_alloc(); + nfc_append_filename_string_when_present(instance, temp_str); + furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_mf_ultralight_info(data, NfcProtocolFormatTypeFull, temp_str); diff --git a/applications/main/nfc/helpers/protocol_support/slix/slix.c b/applications/main/nfc/helpers/protocol_support/slix/slix.c index ad858a75f..04b35578b 100644 --- a/applications/main/nfc/helpers/protocol_support/slix/slix.c +++ b/applications/main/nfc/helpers/protocol_support/slix/slix.c @@ -14,6 +14,7 @@ static void nfc_scene_info_on_enter_slix(NfcApp* instance) { const SlixData* data = nfc_device_get_data(device, NfcProtocolSlix); FuriString* temp_str = furi_string_alloc(); + nfc_append_filename_string_when_present(instance, temp_str); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_slix_info(data, NfcProtocolFormatTypeFull, temp_str); diff --git a/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c b/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c index e22af48b3..8f5826dc4 100644 --- a/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c +++ b/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c @@ -13,6 +13,7 @@ static void nfc_scene_info_on_enter_st25tb(NfcApp* instance) { const St25tbData* data = nfc_device_get_data(device, NfcProtocolSt25tb); FuriString* temp_str = furi_string_alloc(); + nfc_append_filename_string_when_present(instance, temp_str); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_st25tb_info(data, NfcProtocolFormatTypeFull, temp_str); diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 183f49895..29c407b28 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -445,6 +445,15 @@ void nfc_app_reset_detected_protocols(NfcApp* instance) { instance->protocols_detected_num = 0; } +void nfc_append_filename_string_when_present(NfcApp* instance, FuriString* string) { + furi_assert(instance); + furi_assert(string); + + if(!furi_string_empty(instance->file_name)) { + furi_string_cat_printf(string, "Name:%s\n", furi_string_get_cstr(instance->file_name)); + } +} + static bool nfc_is_hal_ready() { if(furi_hal_nfc_is_hal_ready() != FuriHalNfcErrorNone) { // No connection to the chip, show an error screen diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 943d722f8..324ed6a5d 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -192,3 +192,5 @@ void nfc_make_app_folder(NfcApp* instance); void nfc_app_set_detected_protocols(NfcApp* instance, const NfcProtocol* types, uint32_t count); void nfc_app_reset_detected_protocols(NfcApp* instance); + +void nfc_append_filename_string_when_present(NfcApp* instance, FuriString* string); From 9e8e5d8ae978330e28aaa34cbae91c24d56a0d4d Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 17 Jan 2024 20:04:02 +0300 Subject: [PATCH 066/110] New info render format for 14443_3a cards --- .../protocol_support/iso14443_3a/iso14443_3a_render.c | 10 +++++++--- .../protocol_support/iso14443_3a/iso14443_3a_render.h | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.c b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.c index 7306f1072..810242fbc 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.c @@ -6,13 +6,17 @@ void nfc_render_iso14443_3a_format_bytes(FuriString* str, const uint8_t* const d } } +void nfc_render_iso14443_tech_type(const Iso14443_3aData* data, FuriString* str) { + const char iso_type = iso14443_3a_supports_iso14443_4(data) ? '4' : '3'; + furi_string_cat_printf(str, "Tech: ISO 14443-%c (NFC-A)\n", iso_type); +} + void nfc_render_iso14443_3a_info( const Iso14443_3aData* data, NfcProtocolFormatType format_type, FuriString* str) { if(format_type == NfcProtocolFormatTypeFull) { - const char iso_type = iso14443_3a_supports_iso14443_4(data) ? '4' : '3'; - furi_string_cat_printf(str, "ISO 14443-%c (NFC-A)\n", iso_type); + nfc_render_iso14443_tech_type(data, str); } nfc_render_iso14443_3a_brief(data, str); @@ -30,5 +34,5 @@ void nfc_render_iso14443_3a_brief(const Iso14443_3aData* data, FuriString* str) void nfc_render_iso14443_3a_extra(const Iso14443_3aData* data, FuriString* str) { furi_string_cat_printf(str, "\nATQA: %02X %02X ", data->atqa[1], data->atqa[0]); - furi_string_cat_printf(str, "SAK: %02X", data->sak); + furi_string_cat_printf(str, "\nSAK: %02X", data->sak); } diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.h b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.h index 14b91d221..34e347aa3 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.h +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.h @@ -9,6 +9,8 @@ void nfc_render_iso14443_3a_info( NfcProtocolFormatType format_type, FuriString* str); +void nfc_render_iso14443_tech_type(const Iso14443_3aData* data, FuriString* str); + void nfc_render_iso14443_3a_format_bytes(FuriString* str, const uint8_t* const data, size_t size); void nfc_render_iso14443_3a_brief(const Iso14443_3aData* data, FuriString* str); From d9e4a600106f830f640700d916736244adbc312b Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 17 Jan 2024 20:04:59 +0300 Subject: [PATCH 067/110] New info render format for 14443_3b cards --- .../protocol_support/iso14443_3b/iso14443_3b_render.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.c b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.c index 2e81d57a4..ec7efa84f 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.c @@ -6,7 +6,7 @@ void nfc_render_iso14443_3b_info( FuriString* str) { if(format_type == NfcProtocolFormatTypeFull) { const char iso_type = iso14443_3b_supports_iso14443_4(data) ? '4' : '3'; - furi_string_cat_printf(str, "ISO 14443-%c (NFC-B)\n", iso_type); + furi_string_cat_printf(str, "Tech: ISO 14443-%c (NFC-B)\n", iso_type); } furi_string_cat_printf(str, "UID:"); @@ -20,7 +20,7 @@ void nfc_render_iso14443_3b_info( if(format_type != NfcProtocolFormatTypeFull) return; - furi_string_cat_printf(str, "\n\e#Protocol info\n"); + furi_string_cat_printf(str, "\n::::::::::::::::[Protocol info]:::::::::::::::\n"); if(iso14443_3b_supports_bit_rate(data, Iso14443_3bBitRateBoth106Kbit)) { furi_string_cat(str, "Bit rate PICC <-> PCD:\n 106 kBit/s supported\n"); @@ -68,7 +68,7 @@ void nfc_render_iso14443_3b_info( iso14443_3b_supports_frame_option(data, Iso14443_3bFrameOptionCid) ? "" : "not "; furi_string_cat_printf(str, "CID: %ssupported", cid_support_str); - furi_string_cat_printf(str, "\n\e#Application data\nRaw:"); + furi_string_cat_printf(str, "\n::::::::::::[Application data]::::::::::::\nRaw:"); size_t app_data_size; const uint8_t* app_data = iso14443_3b_get_application_data(data, &app_data_size); From dc8b0b02d8f96c2d9947b128b038eb563e71ad83 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 17 Jan 2024 20:05:17 +0300 Subject: [PATCH 068/110] New info render format for 14443_4a cards --- .../protocol_support/iso14443_4a/iso14443_4a_render.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.c b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.c index a963e744b..4ff07d596 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.c @@ -14,11 +14,12 @@ void nfc_render_iso14443_4a_info( } void nfc_render_iso14443_4a_brief(const Iso14443_4aData* data, FuriString* str) { + nfc_render_iso14443_tech_type(iso14443_4a_get_base_data(data), str); nfc_render_iso14443_3a_brief(iso14443_4a_get_base_data(data), str); } void nfc_render_iso14443_4a_extra(const Iso14443_4aData* data, FuriString* str) { - furi_string_cat_printf(str, "\n\e#Protocol info\n"); + furi_string_cat_printf(str, "\n::::::::::::::::[Protocol info]:::::::::::::::\n"); if(iso14443_4a_supports_bit_rate(data, Iso14443_4aBitRateBoth106Kbit)) { furi_string_cat(str, "Bit rate PICC <-> PCD:\n 106 kBit/s supported\n"); @@ -72,7 +73,7 @@ void nfc_render_iso14443_4a_extra(const Iso14443_4aData* data, FuriString* str) const uint8_t* hist_bytes = iso14443_4a_get_historical_bytes(data, &hist_bytes_count); if(hist_bytes_count > 0) { - furi_string_cat_printf(str, "\n\e#Historical bytes\nRaw:"); + furi_string_cat_printf(str, "\n:::::::::::::[Historical bytes]:::::::::::::\nRaw:"); for(size_t i = 0; i < hist_bytes_count; ++i) { furi_string_cat_printf(str, " %02X", hist_bytes[i]); From 61067b0984636bc8d3ca25ddd18cbc52c75a7b0b Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 17 Jan 2024 20:07:15 +0300 Subject: [PATCH 069/110] New info render format for iso15693 cards. Also More_Info scene added to display Memory data --- .../protocol_support/iso15693_3/iso15693_3.c | 21 ++++++- .../iso15693_3/iso15693_3_render.c | 56 ++++++++++--------- .../iso15693_3/iso15693_3_render.h | 2 + 3 files changed, 52 insertions(+), 27 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c index b0110bc29..d645fa3bb 100644 --- a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c @@ -19,12 +19,25 @@ static void nfc_scene_info_on_enter_iso15693_3(NfcApp* instance) { temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_iso15693_3_info(data, NfcProtocolFormatTypeFull, temp_str); + widget_reset(instance->widget); widget_add_text_scroll_element( instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str)); furi_string_free(temp_str); } +static void nfc_scene_more_info_on_enter_iso15693_3(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const Iso15693_3Data* data = nfc_device_get_data(device, NfcProtocolIso15693_3); + + FuriString* temp_str = furi_string_alloc(); + nfc_render_iso15693_3_system_info(data, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); +} + static NfcCommand nfc_scene_read_poller_callback_iso15693_3(NfcGenericEvent event, void* context) { furi_assert(event.protocol == NfcProtocolIso15693_3); @@ -105,13 +118,19 @@ static bool nfc_scene_saved_menu_on_event_iso15693_3(NfcApp* instance, uint32_t } const NfcProtocolSupportBase nfc_protocol_support_iso15693_3 = { - .features = NfcProtocolFeatureEmulateFull | NfcProtocolFeatureEditUid, + .features = NfcProtocolFeatureEmulateFull | NfcProtocolFeatureEditUid | + NfcProtocolFeatureMoreInfo, .scene_info = { .on_enter = nfc_scene_info_on_enter_iso15693_3, .on_event = nfc_protocol_support_common_on_event_empty, }, + .scene_more_info = + { + .on_enter = nfc_scene_more_info_on_enter_iso15693_3, + .on_event = nfc_protocol_support_common_on_event_empty, + }, .scene_read = { .on_enter = nfc_scene_read_on_enter_iso15693_3, diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c index bb2ab92d3..07b96d701 100644 --- a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c @@ -36,32 +36,7 @@ void nfc_render_iso15693_3_brief(const Iso15693_3Data* data, FuriString* str) { } } -void nfc_render_iso15693_3_extra(const Iso15693_3Data* data, FuriString* str) { - furi_string_cat(str, "\n\e#General info\n"); - if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_DSFID) { - furi_string_cat_printf(str, "DSFID: %02X\n", data->system_info.ic_ref); - } - - if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_AFI) { - furi_string_cat_printf(str, "AFI: %02X\n", data->system_info.afi); - } - - if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_IC_REF) { - furi_string_cat_printf(str, "IC Reference: %02X\n", data->system_info.ic_ref); - } - - furi_string_cat(str, "\e#Lock bits\n"); - - if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_DSFID) { - furi_string_cat_printf( - str, "DSFID: %s locked\n", data->settings.lock_bits.dsfid ? "" : "not"); - } - - if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_AFI) { - furi_string_cat_printf( - str, "AFI: %s locked\n", data->settings.lock_bits.dsfid ? "" : "not"); - } - +void nfc_render_iso15693_3_system_info(const Iso15693_3Data* data, FuriString* str) { if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_MEMORY) { furi_string_cat(str, "\e#Memory data\n\e*--------------------\n"); @@ -88,5 +63,34 @@ void nfc_render_iso15693_3_extra(const Iso15693_3Data* data, FuriString* str) { "(Data is too big. Showing only the first %u bytes.)", display_block_count * block_size); } + } else { + furi_string_cat(str, "\e#No available data\n"); + } +} + +void nfc_render_iso15693_3_extra(const Iso15693_3Data* data, FuriString* str) { + furi_string_cat(str, "\n::::::::::::::::[General info]:::::::::::::::::\n"); + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_DSFID) { + furi_string_cat_printf(str, "DSFID: %02X\n", data->system_info.ic_ref); + } + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_AFI) { + furi_string_cat_printf(str, "AFI: %02X\n", data->system_info.afi); + } + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_IC_REF) { + furi_string_cat_printf(str, "IC Reference: %02X\n", data->system_info.ic_ref); + } + + furi_string_cat(str, ":::::::::::::::::::[Lock bits]::::::::::::::::::::\n"); + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_DSFID) { + furi_string_cat_printf( + str, "DSFID: %s locked\n", data->settings.lock_bits.dsfid ? "" : "not"); + } + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_AFI) { + furi_string_cat_printf( + str, "AFI: %s locked\n", data->settings.lock_bits.dsfid ? "" : "not"); } } diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h index d531fd2eb..87100102a 100644 --- a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h @@ -12,3 +12,5 @@ void nfc_render_iso15693_3_info( void nfc_render_iso15693_3_brief(const Iso15693_3Data* data, FuriString* str); void nfc_render_iso15693_3_extra(const Iso15693_3Data* data, FuriString* str); + +void nfc_render_iso15693_3_system_info(const Iso15693_3Data* data, FuriString* str); From 5655be1b8fbbb8e6444c05523744df8ef244dbe0 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 17 Jan 2024 20:07:28 +0300 Subject: [PATCH 070/110] New info render format for slix cards. Also More_Info scene added to display Memory data --- .../nfc/helpers/protocol_support/slix/slix.c | 20 ++++++++++++++++++- .../protocol_support/slix/slix_render.c | 12 +++++------ .../protocol_support/slix/slix_render.h | 1 + 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/slix/slix.c b/applications/main/nfc/helpers/protocol_support/slix/slix.c index 04b35578b..8480f8810 100644 --- a/applications/main/nfc/helpers/protocol_support/slix/slix.c +++ b/applications/main/nfc/helpers/protocol_support/slix/slix.c @@ -19,12 +19,25 @@ static void nfc_scene_info_on_enter_slix(NfcApp* instance) { temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); nfc_render_slix_info(data, NfcProtocolFormatTypeFull, temp_str); + widget_reset(instance->widget); widget_add_text_scroll_element( instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str)); furi_string_free(temp_str); } +static void nfc_scene_more_info_on_enter_slix(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const SlixData* data = nfc_device_get_data(device, NfcProtocolSlix); + + FuriString* temp_str = furi_string_alloc(); + nfc_render_iso15693_3_system_info(slix_get_base_data(data), temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); +} + static NfcCommand nfc_scene_read_poller_callback_slix(NfcGenericEvent event, void* context) { furi_assert(event.protocol == NfcProtocolSlix); @@ -102,13 +115,18 @@ static bool nfc_scene_saved_menu_on_event_slix(NfcApp* instance, uint32_t event) } const NfcProtocolSupportBase nfc_protocol_support_slix = { - .features = NfcProtocolFeatureEmulateFull, + .features = NfcProtocolFeatureEmulateFull | NfcProtocolFeatureMoreInfo, .scene_info = { .on_enter = nfc_scene_info_on_enter_slix, .on_event = nfc_protocol_support_common_on_event_empty, }, + .scene_more_info = + { + .on_enter = nfc_scene_more_info_on_enter_slix, + .on_event = nfc_protocol_support_common_on_event_empty, + }, .scene_read = { .on_enter = nfc_scene_read_on_enter_slix, diff --git a/applications/main/nfc/helpers/protocol_support/slix/slix_render.c b/applications/main/nfc/helpers/protocol_support/slix/slix_render.c index 80f953db9..1be460194 100644 --- a/applications/main/nfc/helpers/protocol_support/slix/slix_render.c +++ b/applications/main/nfc/helpers/protocol_support/slix/slix_render.c @@ -1,14 +1,12 @@ #include "slix_render.h" -#include "../iso15693_3/iso15693_3_render.h" - void nfc_render_slix_info(const SlixData* data, NfcProtocolFormatType format_type, FuriString* str) { nfc_render_iso15693_3_brief(slix_get_base_data(data), str); if(format_type != NfcProtocolFormatTypeFull) return; const SlixType slix_type = slix_get_type(data); - furi_string_cat(str, "\n\e#Passwords\n"); + furi_string_cat(str, "\n::::::::::::::::::[Passwords]:::::::::::::::::\n"); static const char* slix_password_names[] = { "Read", @@ -25,7 +23,7 @@ void nfc_render_slix_info(const SlixData* data, NfcProtocolFormatType format_typ } } - furi_string_cat(str, "\e#Lock bits\n"); + furi_string_cat(str, ":::::::::::::::::::[Lock bits]::::::::::::::::::::\n"); if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_EAS)) { furi_string_cat_printf( @@ -38,7 +36,7 @@ void nfc_render_slix_info(const SlixData* data, NfcProtocolFormatType format_typ const SlixProtection protection = data->system_info.protection; - furi_string_cat(str, "\e#Page protection\n"); + furi_string_cat(str, "::::::::::::[Page protection]::::::::::::\n"); furi_string_cat_printf(str, "Pointer: H >= %02X\n", protection.pointer); const char* rh = (protection.condition & SLIX_PP_CONDITION_RH) ? "" : "un"; @@ -52,12 +50,12 @@ void nfc_render_slix_info(const SlixData* data, NfcProtocolFormatType format_typ } if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_PRIVACY)) { - furi_string_cat(str, "\e#Privacy\n"); + furi_string_cat(str, "::::::::::::::::::::[Privacy]::::::::::::::::::::::\n"); furi_string_cat_printf(str, "Privacy mode: %sabled\n", data->privacy ? "en" : "dis"); } if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_SIGNATURE)) { - furi_string_cat(str, "\e#Signature\n"); + furi_string_cat(str, ":::::::::::::::::::[Signature]::::::::::::::::::\n"); for(uint32_t i = 0; i < 4; ++i) { furi_string_cat_printf(str, "%02X ", data->signature[i]); } diff --git a/applications/main/nfc/helpers/protocol_support/slix/slix_render.h b/applications/main/nfc/helpers/protocol_support/slix/slix_render.h index 98ae6dc97..bfc216382 100644 --- a/applications/main/nfc/helpers/protocol_support/slix/slix_render.h +++ b/applications/main/nfc/helpers/protocol_support/slix/slix_render.h @@ -3,5 +3,6 @@ #include #include "../nfc_protocol_support_render_common.h" +#include "../iso15693_3/iso15693_3_render.h" void nfc_render_slix_info(const SlixData* data, NfcProtocolFormatType format_type, FuriString* str); From ab236f3763f463d4fdfa23b0db25ca0a7d49169a Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 18 Jan 2024 12:52:19 +0300 Subject: [PATCH 071/110] Fixed "Mifare" word for desfire cards --- .../main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c index 9d24a74ec..ef51d98e0 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c @@ -17,6 +17,7 @@ static void nfc_scene_info_on_enter_mf_desfire(NfcApp* instance) { nfc_append_filename_string_when_present(instance, temp_str); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + furi_string_replace(temp_str, "Mifare", "MIFARE"); nfc_render_mf_desfire_info(data, NfcProtocolFormatTypeFull, temp_str); widget_add_text_scroll_element( @@ -57,6 +58,7 @@ static void nfc_scene_read_success_on_enter_mf_desfire(NfcApp* instance) { FuriString* temp_str = furi_string_alloc(); furi_string_cat_printf( temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + furi_string_replace(temp_str, "Mifare", "MIFARE"); nfc_render_mf_desfire_info(data, NfcProtocolFormatTypeShort, temp_str); widget_add_text_scroll_element( From 51f6dcffa421e2d7784ac84c7aad3fa8fbf6af93 Mon Sep 17 00:00:00 2001 From: TollyH Date: Thu, 18 Jan 2024 21:47:38 +0000 Subject: [PATCH 072/110] NFC: Display unread Mifare Classic bytes as ?? --- .../mf_classic/mf_classic_render.c | 52 +++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c index 5bd4a6b6d..bbb96288b 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c @@ -22,9 +22,55 @@ void nfc_render_mf_classic_dump(const MfClassicData* data, FuriString* str) { uint16_t total_blocks = mf_classic_get_total_block_num(data->type); for(size_t i = 0; i < total_blocks; i++) { - for(size_t j = 0; j < sizeof(MfClassicBlock); j += 2) { - furi_string_cat_printf( - str, "%02X%02X ", data->block[i].data[j], data->block[i].data[j + 1]); + const uint8_t* block_data = data->block[i].data; + if(mf_classic_is_block_read(data, i)) { + if(mf_classic_is_sector_trailer(i)) { + uint8_t sector = mf_classic_get_sector_by_block(i); + // Key A + if(mf_classic_is_key_found(data, sector, MfClassicKeyTypeA)) { + furi_string_cat_printf( + str, + "%02X%02X %02X%02X %02X%02X ", + block_data[0], + block_data[1], + block_data[2], + block_data[3], + block_data[4], + block_data[5]); + } else { + furi_string_cat(str, "???? ???? ???? "); + } + // Access bits + furi_string_cat_printf( + str, + "%02X%02X %02X%02X ", + block_data[6], + block_data[7], + block_data[8], + block_data[9]); + // Key B + if(mf_classic_is_key_found(data, sector, MfClassicKeyTypeB)) { + furi_string_cat_printf( + str, + "%02X%02X %02X%02X %02X%02X ", + block_data[10], + block_data[11], + block_data[12], + block_data[13], + block_data[14], + block_data[15]); + } else { + furi_string_cat(str, "???? ???? ???? "); + } + } else { + for(size_t j = 0; j < sizeof(MfClassicBlock); j += 2) { + furi_string_cat_printf(str, "%02X%02X ", block_data[j], block_data[j + 1]); + } + } + } else { + for(size_t j = 0; j < sizeof(MfClassicBlock); j += 2) { + furi_string_cat(str, "???? "); + } } } } From e3930a30c0efdcb32d04c3bc356ee478e49872f3 Mon Sep 17 00:00:00 2001 From: Methodius Date: Sat, 20 Jan 2024 05:00:53 +0900 Subject: [PATCH 073/110] emv parser updated --- .../main/nfc/plugins/supported_cards/emv.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index fabf721ae..cc5465a31 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -885,16 +885,25 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { const EmvApplication app = data->emv_application; do { - furi_string_cat_printf(parsed_data, "\e#AID:\n"); - for(uint8_t i = 0; i < app.aid_len; i++) - furi_string_cat_printf(parsed_data, "%02X ", app.aid[i]); + if(app.name_found) + furi_string_cat_printf(parsed_data, "\e#%s", app.name); + else + furi_string_cat_printf(parsed_data, "\e#%s", "EMV"); + + furi_string_cat_printf(parsed_data, "\nPAN: "); + for(uint8_t i = 0; i < app.pan_len; i++) { + furi_string_cat_printf(parsed_data, "%02X", app.pan[i]); + if((i != 0) && (i % 2 != 0)) furi_string_cat_printf(parsed_data, " "); + } furi_string_cat_printf(parsed_data, "\nCountry: %s", get_country_name(app.country_code)); furi_string_cat_printf( parsed_data, "\nCurrency: %s", get_currency_name(app.currency_code)); - if(app.name_found) furi_string_cat_printf(parsed_data, "\nName: %s", app.name); + furi_string_cat_printf(parsed_data, "\nAID: "); + for(uint8_t i = 0; i < app.aid_len; i++) + furi_string_cat_printf(parsed_data, "%02X", app.aid[i]); parsed = true; } while(false); From b5964b97953a759a0564948ff4f3c6e56fded03f Mon Sep 17 00:00:00 2001 From: Methodius Date: Sat, 20 Jan 2024 05:18:16 +0900 Subject: [PATCH 074/110] Enum order fixes by Willy-JL Co-authored-by: Willy-JL <49810075+Willy-JL@users.noreply.github.com> --- .../protocol_support/nfc_protocol_support_defs.c | 2 +- lib/nfc/protocols/nfc_device_defs.c | 2 +- lib/nfc/protocols/nfc_poller_defs.c | 4 ++-- lib/nfc/protocols/nfc_protocol.c | 12 ++++++------ lib/nfc/protocols/nfc_protocol.h | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c index 9e61585c9..6b42a1660 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c @@ -40,8 +40,8 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = { [NfcProtocolMfUltralight] = &nfc_protocol_support_mf_ultralight, [NfcProtocolMfClassic] = &nfc_protocol_support_mf_classic, [NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire, - [NfcProtocolEmv] = &nfc_protocol_support_emv, [NfcProtocolSlix] = &nfc_protocol_support_slix, [NfcProtocolSt25tb] = &nfc_protocol_support_st25tb, + [NfcProtocolEmv] = &nfc_protocol_support_emv, /* Add new protocol support implementations here */ }; diff --git a/lib/nfc/protocols/nfc_device_defs.c b/lib/nfc/protocols/nfc_device_defs.c index 0dbe8a155..e09523f23 100644 --- a/lib/nfc/protocols/nfc_device_defs.c +++ b/lib/nfc/protocols/nfc_device_defs.c @@ -41,8 +41,8 @@ const NfcDeviceBase* nfc_devices[NfcProtocolNum] = { [NfcProtocolMfUltralight] = &nfc_device_mf_ultralight, [NfcProtocolMfClassic] = &nfc_device_mf_classic, [NfcProtocolMfDesfire] = &nfc_device_mf_desfire, - [NfcProtocolEmv] = &nfc_device_emv, [NfcProtocolSlix] = &nfc_device_slix, [NfcProtocolSt25tb] = &nfc_device_st25tb, + [NfcProtocolEmv] = &nfc_device_emv, /* Add new protocols here */ }; diff --git a/lib/nfc/protocols/nfc_poller_defs.c b/lib/nfc/protocols/nfc_poller_defs.c index 55a59cfd6..e79c96d98 100644 --- a/lib/nfc/protocols/nfc_poller_defs.c +++ b/lib/nfc/protocols/nfc_poller_defs.c @@ -23,8 +23,8 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = { [NfcProtocolMfUltralight] = &mf_ultralight_poller, [NfcProtocolMfClassic] = &mf_classic_poller, [NfcProtocolMfDesfire] = &mf_desfire_poller, - [NfcProtocolEmv] = &emv_poller, [NfcProtocolSlix] = &nfc_poller_slix, - /* Add new pollers here */ [NfcProtocolSt25tb] = &nfc_poller_st25tb, + [NfcProtocolEmv] = &emv_poller, + /* Add new pollers here */ }; diff --git a/lib/nfc/protocols/nfc_protocol.c b/lib/nfc/protocols/nfc_protocol.c index 54ee5ba0d..252f86de2 100644 --- a/lib/nfc/protocols/nfc_protocol.c +++ b/lib/nfc/protocols/nfc_protocol.c @@ -137,12 +137,6 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = { .children_num = 0, .children_protocol = NULL, }, - [NfcProtocolEmv] = - { - .parent_protocol = NfcProtocolIso14443_4a, - .children_num = 0, - .children_protocol = NULL, - }, [NfcProtocolSlix] = { .parent_protocol = NfcProtocolIso15693_3, @@ -155,6 +149,12 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = { .children_num = 0, .children_protocol = NULL, }, + [NfcProtocolEmv] = + { + .parent_protocol = NfcProtocolIso14443_4a, + .children_num = 0, + .children_protocol = NULL, + }, /* Add new protocols here */ }; diff --git a/lib/nfc/protocols/nfc_protocol.h b/lib/nfc/protocols/nfc_protocol.h index d597de152..39e8045fe 100644 --- a/lib/nfc/protocols/nfc_protocol.h +++ b/lib/nfc/protocols/nfc_protocol.h @@ -185,9 +185,9 @@ typedef enum { NfcProtocolMfUltralight, NfcProtocolMfClassic, NfcProtocolMfDesfire, - NfcProtocolEmv, NfcProtocolSlix, NfcProtocolSt25tb, + NfcProtocolEmv, /* Add new protocols here */ NfcProtocolNum, /**< Special value representing the number of available protocols. */ From ecabcbc58adc8eb37cf1408285df6180200e8e0f Mon Sep 17 00:00:00 2001 From: Methodius Date: Sat, 20 Jan 2024 05:35:37 +0900 Subject: [PATCH 075/110] Kostyly for iso14443-4a poller (pwt_ext) Co-authored-by: Nikita Vostokov <1042932+wosk@users.noreply.github.com> --- lib/nfc/helpers/iso14443_4_layer.c | 57 +++++++++++++++++++ lib/nfc/helpers/iso14443_4_layer.h | 6 ++ lib/nfc/protocols/emv/emv_poller_i.c | 8 +-- lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 1 + .../iso14443_4a/iso14443_4a_poller.h | 5 ++ .../iso14443_4a/iso14443_4a_poller_i.c | 38 +++++++++++++ targets/f7/api_symbols.csv | 3 +- 7 files changed, 113 insertions(+), 5 deletions(-) diff --git a/lib/nfc/helpers/iso14443_4_layer.c b/lib/nfc/helpers/iso14443_4_layer.c index 26f4dc3b7..75282c1d6 100644 --- a/lib/nfc/helpers/iso14443_4_layer.c +++ b/lib/nfc/helpers/iso14443_4_layer.c @@ -7,6 +7,18 @@ #define ISO14443_4_BLOCK_PCB_R (5U << 5) #define ISO14443_4_BLOCK_PCB_S (3U << 6) +//KOSTYLY +#define ISO14443_4_BLOCK_PCB_I_ (0U << 6) +#define ISO14443_4_BLOCK_PCB_R_ (2U << 6) +#define ISO14443_4_BLOCK_PCB_TYPE_MASK (3U << 6) +#define ISO14443_4_BLOCK_PCB_S_DESELECT (0U << 4) +#define ISO14443_4_BLOCK_PCB_S_WTX (3U << 4) +#define ISO14443_4_BLOCK_PCB_BLOCK_NUMBER (1U << 0) +#define ISO14443_4_BLOCK_PCB (1U << 1) +#define ISO14443_4_BLOCK_PCB_NAD (1U << 2) +#define ISO14443_4_BLOCK_PCB_CID (1U << 3) +#define ISO14443_4_BLOCK_PCB_CHAINING (1U << 4) + struct Iso14443_4Layer { uint8_t pcb; uint8_t pcb_prev; @@ -62,3 +74,48 @@ bool iso14443_4_layer_decode_block( return ret; } + +Iso14443_4aError iso14443_4_layer_decode_block_pwt_ext( + Iso14443_4Layer* instance, + BitBuffer* output_data, + const BitBuffer* block_data) { + furi_assert(instance); + + Iso14443_4aError ret = Iso14443_4aErrorProtocol; + + do { + const uint8_t pcb_field = bit_buffer_get_byte(block_data, 0); + const uint8_t block_type = pcb_field & ISO14443_4_BLOCK_PCB_TYPE_MASK; + switch(block_type) { + case ISO14443_4_BLOCK_PCB_I_: + if(pcb_field == instance->pcb_prev) { + bit_buffer_copy_right(output_data, block_data, 1); + ret = Iso14443_4aErrorNone; + } else { + // TODO: Need send request again + ret = Iso14443_4aErrorProtocol; + } + break; + case ISO14443_4_BLOCK_PCB_R_: + // TODO + break; + case ISO14443_4_BLOCK_PCB_S: + if((pcb_field & ISO14443_4_BLOCK_PCB_S_WTX) == ISO14443_4_BLOCK_PCB_S_WTX) { + const uint8_t inf_field = bit_buffer_get_byte(block_data, 1); + //const uint8_t power_level = inf_field >> 6; + const uint8_t wtxm = inf_field & 0b111111; + //uint32_t fwt_temp = MIN((fwt * wtxm), fwt_max); + + bit_buffer_reset(output_data); + bit_buffer_append_byte( + output_data, + ISO14443_4_BLOCK_PCB_S | ISO14443_4_BLOCK_PCB_S_WTX | ISO14443_4_BLOCK_PCB); + bit_buffer_append_byte(output_data, wtxm); + ret = Iso14443_4aErrorSendCtrl; + } + break; + } + } while(false); + + return ret; +} \ No newline at end of file diff --git a/lib/nfc/helpers/iso14443_4_layer.h b/lib/nfc/helpers/iso14443_4_layer.h index 712173ce1..14e435c2f 100644 --- a/lib/nfc/helpers/iso14443_4_layer.h +++ b/lib/nfc/helpers/iso14443_4_layer.h @@ -1,5 +1,6 @@ #pragma once +#include "protocols/iso14443_4a/iso14443_4a.h" #include #ifdef __cplusplus @@ -24,6 +25,11 @@ bool iso14443_4_layer_decode_block( BitBuffer* output_data, const BitBuffer* block_data); +Iso14443_4aError iso14443_4_layer_decode_block_pwt_ext( + Iso14443_4Layer* instance, + BitBuffer* output_data, + const BitBuffer* block_data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 9494ca199..7e85c7dcc 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -261,7 +261,7 @@ EmvError emv_poller_select_ppse(EmvPoller* instance) { do { FURI_LOG_D(TAG, "Send select PPSE"); - Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( + Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block_pwt_ext( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); if(iso14443_4a_error != Iso14443_4aErrorNone) { @@ -313,7 +313,7 @@ EmvError emv_poller_select_application(EmvPoller* instance) { do { FURI_LOG_D(TAG, "Start application"); - Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( + Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block_pwt_ext( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); emv_trace(instance, "Start application answer:"); @@ -365,7 +365,7 @@ EmvError emv_poller_get_processing_options(EmvPoller* instance) { do { FURI_LOG_D(TAG, "Get proccessing options"); - Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( + Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block_pwt_ext( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); emv_trace(instance, "Get processing options answer:"); @@ -408,7 +408,7 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re bit_buffer_copy_bytes(instance->tx_buffer, emv_sfi_header, sizeof(emv_sfi_header)); do { - Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( + Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block_pwt_ext( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); emv_trace(instance, "SFI record:"); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index df212152d..add93cea1 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -13,6 +13,7 @@ typedef enum { Iso14443_4aErrorNotPresent, Iso14443_4aErrorProtocol, Iso14443_4aErrorTimeout, + Iso14443_4aErrorSendCtrl, } Iso14443_4aError; typedef enum { diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h index fef565e51..019beb2be 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h @@ -56,6 +56,11 @@ Iso14443_4aError iso14443_4a_poller_send_block( const BitBuffer* tx_buffer, BitBuffer* rx_buffer); +Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext( + Iso14443_4aPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer); + /** * @brief Send HALT command to the card. * diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index 938e4e715..529c74e27 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -81,3 +81,41 @@ Iso14443_4aError iso14443_4a_poller_send_block( return error; } + +Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext( + Iso14443_4aPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer) { + furi_assert(instance); + + bit_buffer_reset(instance->tx_buffer); + iso14443_4_layer_encode_block(instance->iso14443_4_layer, tx_buffer, instance->tx_buffer); + + Iso14443_4aError error = Iso14443_4aErrorNone; + + do { + bit_buffer_reset(instance->rx_buffer); + Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standard_frame( + instance->iso14443_3a_poller, + instance->tx_buffer, + instance->rx_buffer, + iso14443_4a_get_fwt_fc_max(instance->data)); + + if(iso14443_3a_error != Iso14443_3aErrorNone) { + error = iso14443_4a_process_error(iso14443_3a_error); + break; + + } else { + error = iso14443_4_layer_decode_block_pwt_ext( + instance->iso14443_4_layer, rx_buffer, instance->rx_buffer); + if(error == Iso14443_4aErrorSendCtrl) { + // Send response for Control message + bit_buffer_copy(instance->tx_buffer, rx_buffer); + continue; + } + break; + } + } while(true); + + return error; +} \ No newline at end of file diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 95b0bd5cd..1976ef2de 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,51.0,, +Version,+,52.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -1969,6 +1969,7 @@ Function,+,iso14443_4a_load,_Bool,"Iso14443_4aData*, FlipperFormat*, uint32_t" Function,+,iso14443_4a_poller_halt,Iso14443_4aError,Iso14443_4aPoller* Function,+,iso14443_4a_poller_read_ats,Iso14443_4aError,"Iso14443_4aPoller*, Iso14443_4aAtsData*" Function,+,iso14443_4a_poller_send_block,Iso14443_4aError,"Iso14443_4aPoller*, const BitBuffer*, BitBuffer*" +Function,+,iso14443_4a_poller_send_block_pwt_ext,Iso14443_4aError,"Iso14443_4aPoller*, const BitBuffer*, BitBuffer*" Function,+,iso14443_4a_reset,void,Iso14443_4aData* Function,+,iso14443_4a_save,_Bool,"const Iso14443_4aData*, FlipperFormat*" Function,+,iso14443_4a_set_uid,_Bool,"Iso14443_4aData*, const uint8_t*, size_t" From 5f041a22e56ef3a85a3fb431cffff1274e67cf3b Mon Sep 17 00:00:00 2001 From: Methodius Date: Sat, 20 Jan 2024 06:39:34 +0900 Subject: [PATCH 076/110] EMV parser: exp date added --- applications/main/nfc/plugins/supported_cards/emv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index cc5465a31..deb693755 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -896,6 +896,8 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { if((i != 0) && (i % 2 != 0)) furi_string_cat_printf(parsed_data, " "); } + furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X", app.exp_month, app.exp_year); + furi_string_cat_printf(parsed_data, "\nCountry: %s", get_country_name(app.country_code)); furi_string_cat_printf( From 84abb537121ed2489b71787ea2a9c4f1b48c7aa7 Mon Sep 17 00:00:00 2001 From: Methodius Date: Tue, 23 Jan 2024 19:51:59 +0900 Subject: [PATCH 077/110] Track2 support Co-authored-by: Nikita Vostokov <1042932+wosk@users.noreply.github.com> --- .../main/nfc/plugins/supported_cards/emv.c | 4 +- lib/nfc/protocols/emv/emv.h | 8 +- lib/nfc/protocols/emv/emv_poller_i.c | 77 ++++++++++++++----- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index deb693755..703a98cb6 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -890,10 +890,10 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { else furi_string_cat_printf(parsed_data, "\e#%s", "EMV"); - furi_string_cat_printf(parsed_data, "\nPAN: "); + furi_string_cat_printf(parsed_data, "\nPAN:"); for(uint8_t i = 0; i < app.pan_len; i++) { + if((i % 2 == 0)) furi_string_cat_printf(parsed_data, " "); furi_string_cat_printf(parsed_data, "%02X", app.pan[i]); - if((i != 0) && (i % 2 != 0)) furi_string_cat_printf(parsed_data, " "); } furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X", app.exp_month, app.exp_year); diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index a10450b7e..c7463ab98 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -14,7 +14,7 @@ extern "C" { #define EMV_TAG_PDOL 0x9F38 #define EMV_TAG_CARD_NAME 0x50 #define EMV_TAG_FCI 0xBF0C -#define EMV_TAG_LOG_CTRL 0x9F4D +#define EMV_TAG_LOG_ENTRY 0x9F4D #define EMV_TAG_TRACK_1_EQUIV 0x56 #define EMV_TAG_TRACK_2_EQUIV 0x57 #define EMV_TAG_PAN 0x5A @@ -23,6 +23,10 @@ extern "C" { #define EMV_TAG_COUNTRY_CODE 0x5F28 #define EMV_TAG_CURRENCY_CODE 0x9F42 #define EMV_TAG_CARDHOLDER_NAME 0x5F20 +#define EMV_TAG_TRACK_2_DATA 0x9F6B + +#define EMV_TAG_RESP_BUF_SIZE 0x6C +#define EMV_TAG_GPO_FMT1 0x80 typedef struct { uint16_t tag; @@ -35,6 +39,8 @@ typedef struct { } APDU; typedef struct { + uint8_t log_sfi; + uint8_t log_records; uint8_t priority; uint8_t aid[16]; uint8_t aid_len; diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 7e85c7dcc..2b9bdc6e0 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -145,15 +145,34 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio } } else { switch(tag) { + case EMV_TAG_GPO_FMT1: + // skip AIP + i += 2; + tlen -= 2; + memcpy(app->afl.data, &buff[i], tlen); + app->afl.size = tlen; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_GPO_FMT1 %X: ", tag); + break; + case EMV_TAG_RESP_BUF_SIZE: + //success = true; + FURI_LOG_T(TAG, "found EMV_TAG_RESP_BUF_SIZE %X: %d", tag, buff[i]); + // Need to request SFI again with this length value + break; case EMV_TAG_AID: app->aid_len = tlen; memcpy(app->aid, &buff[i], tlen); success = true; - FURI_LOG_T(TAG, "found EMV_TAG_AID %x", tag); + FURI_LOG_T(TAG, "found EMV_TAG_AID %X: ", tag); + for(size_t x = 0; x < tlen; x++) { + FURI_LOG_RAW_T("%02X ", app->aid[x]); + } + FURI_LOG_RAW_T("\r\n"); break; case EMV_TAG_PRIORITY: memcpy(&app->priority, &buff[i], tlen); success = true; + FURI_LOG_T(TAG, "found EMV_TAG_APP_PRIORITY %X: %d", tag, app->priority); break; case EMV_TAG_CARD_NAME: memcpy(app->name, &buff[i], tlen); @@ -174,7 +193,9 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio success = true; FURI_LOG_T(TAG, "found EMV_TAG_AFL %x (len=%d)", tag, tlen); break; + // Tracks data https://murdoch.is/papers/defcon20emvdecode.pdf case EMV_TAG_TRACK_1_EQUIV: { + // Contain PAN and expire date char track_1_equiv[80]; memcpy(track_1_equiv, &buff[i], tlen); track_1_equiv[tlen] = '\0'; @@ -182,8 +203,9 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio FURI_LOG_T(TAG, "found EMV_TAG_TRACK_1_EQUIV %x : %s", tag, track_1_equiv); break; } + case EMV_TAG_TRACK_2_DATA: case EMV_TAG_TRACK_2_EQUIV: { - FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2_EQUIV %x", tag); + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2 %X", tag); // 0xD0 delimits PAN from expiry (YYMM) for(int x = 1; x < tlen; x++) { if(buff[i + x + 1] > 0xD0) { @@ -195,21 +217,21 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio } } - // // Convert 4-bit to ASCII representation - // char track_2_equiv[41]; - // uint8_t track_2_equiv_len = 0; - // for(int x = 0; x < tlen; x++) { - // char top = (buff[i + x] >> 4) + '0'; - // char bottom = (buff[i + x] & 0x0F) + '0'; - // track_2_equiv[x * 2] = top; - // track_2_equiv_len++; - // if(top == '?') break; - // track_2_equiv[x * 2 + 1] = bottom; - // track_2_equiv_len++; - // if(bottom == '?') break; - // } - // track_2_equiv[track_2_equiv_len] = '\0'; - // FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2_EQUIV %x : %s", tag, track_2_equiv); + // Convert 4-bit to ASCII representation + char track_2_equiv[41]; + uint8_t track_2_equiv_len = 0; + for(int x = 0; x < tlen; x++) { + char top = (buff[i + x] >> 4) + '0'; + char bottom = (buff[i + x] & 0x0F) + '0'; + track_2_equiv[x * 2] = top; + track_2_equiv_len++; + if(top == '?') break; + track_2_equiv[x * 2 + 1] = bottom; + track_2_equiv_len++; + if(bottom == '?') break; + } + track_2_equiv[track_2_equiv_len] = '\0'; + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2 %X : %s", tag, track_2_equiv); success = true; break; } @@ -235,6 +257,17 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio success = true; FURI_LOG_T(TAG, "found EMV_TAG_COUNTRY_CODE %x", tag); break; + case EMV_TAG_LOG_ENTRY: + app->log_sfi = buff[i]; + app->log_records = buff[i + 1]; + success = true; + FURI_LOG_T( + TAG, + "found EMV_TAG_LOG_ENTRY %x: sfi 0x%x, records %d", + tag, + app->log_sfi, + app->log_records); + break; } } i += tlen; @@ -392,6 +425,7 @@ EmvError emv_poller_get_processing_options(EmvPoller* instance) { EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t record_num) { EmvError error = EmvErrorNone; + FuriString* text = furi_string_alloc(); uint8_t sfi_param = (sfi << 3) | (1 << 2); uint8_t emv_sfi_header[] = { @@ -411,10 +445,11 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block_pwt_ext( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); - emv_trace(instance, "SFI record:"); + furi_string_printf(text, "SFI 0x%X record %d:", sfi, record_num); + emv_trace(instance, furi_string_get_cstr(text)); if(iso14443_4a_error != Iso14443_4aErrorNone) { - FURI_LOG_E(TAG, "Failed to read SFI %d record %d", sfi, record_num); + FURI_LOG_E(TAG, "Failed to read SFI 0x%X record %d", sfi, record_num); error = emv_process_error(iso14443_4a_error); break; } @@ -427,10 +462,12 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re &instance->data->emv_application)) { // It's ok while bruteforcing //error = EmvErrorProtocol; - FURI_LOG_T(TAG, "Failed to parse SFI %d record %d", sfi, record_num); + FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record_num); } } while(false); + furi_string_free(text); + return error; } From c470748e3f11afe67d775efbb732ba7f494bd95b Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 23 Jan 2024 14:00:45 +0300 Subject: [PATCH 078/110] Aligned text and replaced dolphin image on emulate scene --- .../protocol_support/nfc_protocol_support.c | 9 +++++---- assets/icons/NFC/NFC_dolphin_emulation_47x61.png | Bin 1541 -> 0 bytes assets/icons/NFC/NFC_dolphin_emulation_51x64.png | Bin 0 -> 1591 bytes 3 files changed, 5 insertions(+), 4 deletions(-) delete mode 100644 assets/icons/NFC/NFC_dolphin_emulation_47x61.png create mode 100644 assets/icons/NFC/NFC_dolphin_emulation_51x64.png diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index c87ee613f..fb45f65b9 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -565,11 +565,11 @@ static void nfc_protocol_support_scene_emulate_on_enter(NfcApp* instance) { FuriString* temp_str = furi_string_alloc(); const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); - widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61); + widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_51x64); if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateUid)) { widget_add_string_element( - widget, 90, 13, AlignCenter, AlignTop, FontPrimary, "Emulating UID"); + widget, 90, 28, AlignCenter, AlignCenter, FontPrimary, "Emulating UID"); size_t uid_len; const uint8_t* uid = nfc_device_get_uid(instance->nfc_device, &uid_len); @@ -581,7 +581,8 @@ static void nfc_protocol_support_scene_emulate_on_enter(NfcApp* instance) { furi_string_trim(temp_str); } else { - widget_add_string_element(widget, 90, 13, AlignCenter, AlignTop, FontPrimary, "Emulating"); + widget_add_string_element( + widget, 90, 28, AlignCenter, AlignCenter, FontPrimary, "Emulating"); if(!furi_string_empty(instance->file_name)) { furi_string_set(temp_str, instance->file_name); } else { @@ -593,7 +594,7 @@ static void nfc_protocol_support_scene_emulate_on_enter(NfcApp* instance) { } widget_add_text_box_element( - widget, 56, 28, 71, 25, AlignCenter, AlignTop, furi_string_get_cstr(temp_str), false); + widget, 56, 30, 71, 25, AlignCenter, AlignCenter, furi_string_get_cstr(temp_str), false); furi_string_free(temp_str); diff --git a/assets/icons/NFC/NFC_dolphin_emulation_47x61.png b/assets/icons/NFC/NFC_dolphin_emulation_47x61.png deleted file mode 100644 index 1783531285bed514517fc0821501e718359dd765..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1541 zcmaJ>eM}Q)7{3ZaLqs>76Ex1V5{uLJ`hl&zQLyxiR4J5Flue0VuU9zXKDZvVFu$in zjZPV|k*WB>lBo=wab{s;0v4vrHgq6yL6|@s=rj(*ZALe`w+OgD#xD2qyib0=-}CW4 z_wKW%tO^gC8wNp8xH$>4fiD6cy*LQG!v-3sLy!oej7F>3XoNYQby0aF1bI7aN-wPT zSzjw@m}hD^wN~8M!%5Suc^yp$% z;LAJvZZ<7U;$}9n&swkday_9{j$6k|(n<`UWz^qKx;6aE!&&NN(Msv}w)zef+FQ1w zPdX)Tbt_@>_j_ z1g4yN$-3nhg@rScIaE?HPo@{A*oop?Lg$pk$HB2)6bR6yfWuxok8z`3y<}7u1$MxV zNZ?V3kgJ!xNGj7}g^esv!dkgfMko{tSgVthPF&?syKrI|tWv0yh!WgdnNo|Y)TmMi zk6jWFkaxOJ8D8>lEl2;>9^cDOUul8V6b|{|}|<3A9_V zkuUT8Phq#ch$9gj>1GRf0_>e@Q6LnD8hH{ISl-UEdE_v6wo9ijB}kYxrRx(fq|eo5E&zRs*rRh@+=LHR*h1V=c1idZ;b1lJeL)dauJXW z64={+?e(||3{b$F7+$cL7=MxhGtYzJp6B{075o?>)?~ZM@Am^U<4XHBa7ryUV+Omo z^NSB}*9I*Vo3i}=cBw9McHOY`cJjO|@#%;8vhG*t42yEl!M7sbnHFlhs_u%cu{BLw zhaGH~)>1i`aAdfxzb-yDYp8axDf-aUrDb=dji35@J+L(5s-gM3W`<^_YQ(SZsXOZ| z+MW^|z2V5B)@@rgjw-Cq(dw%_ar$zq^bB!0SN!Wu`o1~8yPWDctj)SpoN(-94Cmev zzx{^qT>j%Hhc_onj|mkQqEx+SO=({jC(e}(-Mu#TV*2AZM;fP!-l&6{t3IlprLTNH zu7%|!`|gA}!?~;;lRx5Kde1<}Db&?0+p;8mU68o-2TkKA6-h@we_Yd@SR^HGPk zTw<~x)L!ghDi?=TUtd5z8164@t6%c>#|vtn#`%LIpusI7pJ(MpaIQm;*_49SCT!aE E4{AO|uK)l5 diff --git a/assets/icons/NFC/NFC_dolphin_emulation_51x64.png b/assets/icons/NFC/NFC_dolphin_emulation_51x64.png new file mode 100644 index 0000000000000000000000000000000000000000..ad5646d16459cbeba7b19f63b5afb6db21f819f3 GIT binary patch literal 1591 zcmeAS@N?(olHy`uVBq!ia0vp^#z5@A!3-oDPVO&fU|`hGbaoE#baqxKD9TUE%t>Wn zsJOLu;zqB-0U~YtrCpCM4C8q8pg=t^Am{4A9?$45g^1P8lh%4VPrama=gz8H4)^VR zdhhHSCog`m;0MdT#z$8UDtZ(M9nAlA?)<}o2keWJuFq`?Y;#-_y8ETa_0Lb=2pjt_ zI;fus+I`iEp<}YeBXuUbctM8qv&-&gelUM_I3zQHDW`m~4oe{8FLA4@3db5GzXbC> z;xoAFxtr|~qsG^wdPXnDcli#UJLmB~Vm7E=_q^GVeTL&Z?S_?$y?Fz?FHN+1JvS?I ztB&`ryDA+|K5AUPs4)3=;fxg~fwHotjeqPJ#6BM_yF4*F^z^Oh=kp6~v4q}24xJX@vryZ0+8WTx0Eg`4^s_!c;)W@LI)6{QAO z`Gq7`WhYyvDB0U7*i={n4aiL`NmQuF&B-gas<2f8n`;GRgM{^!6u?SKvTc#AbGt^BsFfdXux715BHZ@62OEx#qQ7|$vGS)XV)HkryH8ip^Ftsu@R)7K} zpoK*#X;wilZcyuhJX@uVl9B=|ef{$Ca=mh6z5JqdeM3u2OML?)eIp}XpbFjM%Dj@q z3f;V7Wta&rsl~}fnFS@8`FRQ;6BCp2OG|8(fR2UuBDVl;Y+f-mq<~?jUy)d#Z>VPg z@)b;>uP=V3xw&xF#U(+h2=`(&xHzP;AXPsowK%`DC>a=cY04n03ap%qQWHz^i$e1A zb6^1(kda@KU!0L&pkQRGXQH413OGX}19QDxJtGq%GX)b%(z*Q}aq-dQ%X3O>pW3rIp+Qpv^9+MVV!(DQ-pixeDL_vC72l7DJro zLG`BKc8d{Cz4}1M=!2piDH*_ofN2ZFgr{pD2c9!h^MKi*2$=3;z1JuL^9);nPl)UP z|Nnu^&_kE&fCZSXr;B4q#jQQlIQf_qd0c5+MXOX$CUrGc&h{NFs!LOA8_nM2jgySt!IBFjn)|4o^*9%oVS*X zZ0??}n8{i*U;Ri9Uic<}|l_6;w1%IPg#Ybbe;UU!j&K6%UWKMy2+v zd+;yhlYZ_kTP_hFZXj~h;=H7@?t!?7<+Cq)1TE_njXLwt{|dW`N6ZgNp{aEbcu&4{ z?-7XAk9w%%Qq`HH9p(6A`#fReDXS{?wu*1&4cg@tlrG*P{m)}d-osblSZ)cuotM$v zPwW5H$pSs;NycL(D`2Zwc+K;@CAtDnm{r-UW| Dsjf_~ literal 0 HcmV?d00001 From 74023e43cebc579ac23e8fec0f2f644dbd45c26e Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 23 Jan 2024 18:08:17 +0300 Subject: [PATCH 079/110] Fixed Mifare caption after QA --- applications/main/nfc/scenes/nfc_scene_select_protocol.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/applications/main/nfc/scenes/nfc_scene_select_protocol.c b/applications/main/nfc/scenes/nfc_scene_select_protocol.c index 7a5d12521..52b2664ec 100644 --- a/applications/main/nfc/scenes/nfc_scene_select_protocol.c +++ b/applications/main/nfc/scenes/nfc_scene_select_protocol.c @@ -29,6 +29,8 @@ void nfc_scene_select_protocol_on_enter(void* context) { "%s %s", prefix, nfc_device_get_protocol_name(instance->protocols_detected[i])); + + furi_string_replace_str(temp_str, "Mifare", "MIFARE"); submenu_add_item( submenu, furi_string_get_cstr(temp_str), From 391c32654bd680a019b6dc1c755b2203f195ca77 Mon Sep 17 00:00:00 2001 From: TollyH Date: Tue, 23 Jan 2024 17:17:37 +0000 Subject: [PATCH 080/110] Apply patch from @gornekich --- .../mf_classic/mf_classic_render.c | 89 ++++++++----------- 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c index bbb96288b..0382b3333 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c @@ -18,59 +18,48 @@ void nfc_render_mf_classic_info( furi_string_cat_printf(str, "\nSectors Read: %u/%u", sectors_read, sectors_total); } +static void + mf_classic_render_raw_data(const uint8_t* data, size_t size, bool data_read, FuriString* str) { + furi_assert((size % 2) == 0); + + for(size_t i = 0; i < size; i += 2) { + if(data_read) { + furi_string_cat_printf(str, "%02X%02X ", data[i], data[i + 1]); + } else { + furi_string_cat_printf(str, "???? "); + } + } +} + +static void + mf_classic_render_block(const MfClassicData* data, uint8_t block_num, FuriString* str) { + if(mf_classic_is_sector_trailer(block_num)) { + uint8_t sec_num = mf_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sec_num); + + // Render key A + bool key_read = mf_classic_is_key_found(data, sec_num, MfClassicKeyTypeA); + mf_classic_render_raw_data(sec_tr->key_a.data, sizeof(MfClassicKey), key_read, str); + + // Render access bits + bool access_bits_read = mf_classic_is_block_read(data, block_num); + mf_classic_render_raw_data( + sec_tr->access_bits.data, sizeof(MfClassicAccessBits), access_bits_read, str); + + // Render key B + key_read = mf_classic_is_key_found(data, sec_num, MfClassicKeyTypeB); + mf_classic_render_raw_data(sec_tr->key_b.data, sizeof(MfClassicKey), key_read, str); + } else { + const uint8_t* block_data = data->block[block_num].data; + bool block_read = mf_classic_is_block_read(data, block_num); + mf_classic_render_raw_data(block_data, sizeof(MfClassicBlock), block_read, str); + } +} + void nfc_render_mf_classic_dump(const MfClassicData* data, FuriString* str) { uint16_t total_blocks = mf_classic_get_total_block_num(data->type); for(size_t i = 0; i < total_blocks; i++) { - const uint8_t* block_data = data->block[i].data; - if(mf_classic_is_block_read(data, i)) { - if(mf_classic_is_sector_trailer(i)) { - uint8_t sector = mf_classic_get_sector_by_block(i); - // Key A - if(mf_classic_is_key_found(data, sector, MfClassicKeyTypeA)) { - furi_string_cat_printf( - str, - "%02X%02X %02X%02X %02X%02X ", - block_data[0], - block_data[1], - block_data[2], - block_data[3], - block_data[4], - block_data[5]); - } else { - furi_string_cat(str, "???? ???? ???? "); - } - // Access bits - furi_string_cat_printf( - str, - "%02X%02X %02X%02X ", - block_data[6], - block_data[7], - block_data[8], - block_data[9]); - // Key B - if(mf_classic_is_key_found(data, sector, MfClassicKeyTypeB)) { - furi_string_cat_printf( - str, - "%02X%02X %02X%02X %02X%02X ", - block_data[10], - block_data[11], - block_data[12], - block_data[13], - block_data[14], - block_data[15]); - } else { - furi_string_cat(str, "???? ???? ???? "); - } - } else { - for(size_t j = 0; j < sizeof(MfClassicBlock); j += 2) { - furi_string_cat_printf(str, "%02X%02X ", block_data[j], block_data[j + 1]); - } - } - } else { - for(size_t j = 0; j < sizeof(MfClassicBlock); j += 2) { - furi_string_cat(str, "???? "); - } - } + mf_classic_render_block(data, i, str); } } From 1ad17878e3928996cddde653dfd0bdbc287dd38d Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 23 Jan 2024 22:33:04 +0300 Subject: [PATCH 081/110] Changed event handler signature. Now we put whole SceneManagerEvent not only custom event. --- .../nfc/helpers/protocol_support/nfc_protocol_support_base.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h index 69a6d34d2..eec736ca2 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h @@ -7,6 +7,7 @@ #include #include "../../nfc_app.h" +#include "../../nfc_app_i.h" /** * @brief Scene entry handler. @@ -19,10 +20,10 @@ typedef void (*NfcProtocolSupportOnEnter)(NfcApp* instance); * @brief Scene event handler. * * @param[in,out] instance pointer to the NFC application instance. - * @param[in] event custom event that has occurred. + * @param[in] event scene manager event that has occurred. * @returns true if the event was handled, false otherwise. */ -typedef bool (*NfcProtocolSupportOnEvent)(NfcApp* instance, uint32_t event); +typedef bool (*NfcProtocolSupportOnEvent)(NfcApp* instance, SceneManagerEvent event); /** * @brief Abstract scene interface. From 9fb14704c3e552ac071c25f4538711a6a7ca068b Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 23 Jan 2024 22:33:55 +0300 Subject: [PATCH 082/110] Changed signature and implementation of common on_event callback --- .../protocol_support/nfc_protocol_support_gui_common.c | 4 ++-- .../protocol_support/nfc_protocol_support_gui_common.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c index f3a855125..620fd48ff 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c @@ -35,8 +35,8 @@ void nfc_protocol_support_common_on_enter_empty(NfcApp* instance) { UNUSED(instance); } -bool nfc_protocol_support_common_on_event_empty(NfcApp* instance, uint32_t event) { +bool nfc_protocol_support_common_on_event_empty(NfcApp* instance, SceneManagerEvent event) { UNUSED(instance); UNUSED(event); - return true; + return event.type != SceneManagerEventTypeBack ? true : false; } diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h index 40ba40c8e..3230f1a7e 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h @@ -7,6 +7,7 @@ #include #include "nfc/nfc_app.h" +#include "nfc/nfc_app_i.h" /** * @brief Common submenu indices. @@ -82,4 +83,4 @@ void nfc_protocol_support_common_on_enter_empty(NfcApp* instance); * @param[in] event custom event type that has occurred. * @returns always true. */ -bool nfc_protocol_support_common_on_event_empty(NfcApp* instance, uint32_t event); +bool nfc_protocol_support_common_on_event_empty(NfcApp* instance, SceneManagerEvent event); From aad9f6be287811630a964cb15616fd7b8bf2e9a5 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 23 Jan 2024 22:39:25 +0300 Subject: [PATCH 083/110] Changes required due to event signature adjustment --- .../helpers/protocol_support/felica/felica.c | 4 +- .../iso14443_3a/iso14443_3a.c | 4 +- .../iso14443_3b/iso14443_3b.c | 6 +-- .../iso14443_3b/iso14443_3b_i.h | 2 +- .../iso14443_4a/iso14443_4a.c | 4 +- .../iso14443_4b/iso14443_4b.c | 6 +-- .../protocol_support/iso15693_3/iso15693_3.c | 4 +- .../protocol_support/mf_classic/mf_classic.c | 35 +++++++++-------- .../mf_ultralight/mf_ultralight.c | 39 +++++++++++-------- .../protocol_support/nfc_protocol_support.c | 21 ++++------ .../nfc/helpers/protocol_support/slix/slix.c | 4 +- .../helpers/protocol_support/st25tb/st25tb.c | 4 +- 12 files changed, 68 insertions(+), 65 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/felica/felica.c b/applications/main/nfc/helpers/protocol_support/felica/felica.c index f9c849121..cdfb53794 100644 --- a/applications/main/nfc/helpers/protocol_support/felica/felica.c +++ b/applications/main/nfc/helpers/protocol_support/felica/felica.c @@ -58,8 +58,8 @@ static void nfc_scene_read_success_on_enter_felica(NfcApp* instance) { furi_string_free(temp_str); } -static bool nfc_scene_saved_menu_on_event_felica(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexCommonEdit) { +static bool nfc_scene_saved_menu_on_event_felica(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexCommonEdit) { scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); return true; } diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c index c0d502d03..f5830fa9b 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c @@ -95,8 +95,8 @@ static void nfc_scene_emulate_on_enter_iso14443_3a(NfcApp* instance) { instance->listener, nfc_scene_emulate_listener_callback_iso14443_3a, instance); } -static bool nfc_scene_read_menu_on_event_iso14443_3a(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexCommonEmulate) { +static bool nfc_scene_read_menu_on_event_iso14443_3a(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexCommonEmulate) { scene_manager_next_scene(instance->scene_manager, NfcSceneEmulate); return true; } diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c index fee231846..bb3751fc8 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c @@ -59,8 +59,8 @@ static void nfc_scene_read_success_on_enter_iso14443_3b(NfcApp* instance) { furi_string_free(temp_str); } -bool nfc_scene_saved_menu_on_event_iso14443_3b_common(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexCommonEdit) { +bool nfc_scene_saved_menu_on_event_iso14443_3b_common(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexCommonEdit) { scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); return true; } @@ -68,7 +68,7 @@ bool nfc_scene_saved_menu_on_event_iso14443_3b_common(NfcApp* instance, uint32_t return false; } -static bool nfc_scene_saved_menu_on_event_iso14443_3b(NfcApp* instance, uint32_t event) { +static bool nfc_scene_saved_menu_on_event_iso14443_3b(NfcApp* instance, SceneManagerEvent event) { return nfc_scene_saved_menu_on_event_iso14443_3b_common(instance, event); } diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_i.h b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_i.h index 53fe6b392..6c7c2a0bc 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_i.h +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_i.h @@ -4,4 +4,4 @@ #include "iso14443_3b.h" -bool nfc_scene_saved_menu_on_event_iso14443_3b_common(NfcApp* instance, uint32_t event); +bool nfc_scene_saved_menu_on_event_iso14443_3b_common(NfcApp* instance, SceneManagerEvent event); diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c index 0a3a592e1..015f32ed5 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c @@ -99,8 +99,8 @@ static void nfc_scene_emulate_on_enter_iso14443_4a(NfcApp* instance) { instance->listener, nfc_scene_emulate_listener_callback_iso14443_4a, instance); } -static bool nfc_scene_read_menu_on_event_iso14443_4a(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexCommonEmulate) { +static bool nfc_scene_read_menu_on_event_iso14443_4a(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexCommonEmulate) { scene_manager_next_scene(instance->scene_manager, NfcSceneEmulate); return true; } diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4b/iso14443_4b.c b/applications/main/nfc/helpers/protocol_support/iso14443_4b/iso14443_4b.c index a0c70a22e..965cbc8dd 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_4b/iso14443_4b.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4b/iso14443_4b.c @@ -64,8 +64,8 @@ static void nfc_scene_saved_menu_on_enter_iso14443_4b(NfcApp* instance) { UNUSED(instance); } -static bool nfc_scene_read_menu_on_event_iso14443_4b(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexCommonEmulate) { +static bool nfc_scene_read_menu_on_event_iso14443_4b(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexCommonEmulate) { scene_manager_next_scene(instance->scene_manager, NfcSceneEmulate); return true; } @@ -73,7 +73,7 @@ static bool nfc_scene_read_menu_on_event_iso14443_4b(NfcApp* instance, uint32_t return false; } -static bool nfc_scene_saved_menu_on_event_iso14443_4b(NfcApp* instance, uint32_t event) { +static bool nfc_scene_saved_menu_on_event_iso14443_4b(NfcApp* instance, SceneManagerEvent event) { return nfc_scene_saved_menu_on_event_iso14443_3b_common(instance, event); } diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c index 7f861a032..109278752 100644 --- a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c @@ -94,8 +94,8 @@ static void nfc_scene_emulate_on_enter_iso15693_3(NfcApp* instance) { instance->listener, nfc_scene_emulate_listener_callback_iso15693_3, instance); } -static bool nfc_scene_saved_menu_on_event_iso15693_3(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexCommonEdit) { +static bool nfc_scene_saved_menu_on_event_iso15693_3(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexCommonEdit) { scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); return true; } diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index 7feeccf22..c771df8dc 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -99,8 +99,9 @@ static void nfc_scene_read_on_enter_mf_classic(NfcApp* instance) { nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_mf_classic, instance); } -static bool nfc_scene_read_on_event_mf_classic(NfcApp* instance, uint32_t event) { - if(event == NfcCustomEventPollerIncomplete) { +static bool nfc_scene_read_on_event_mf_classic(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom && + event.event == NfcCustomEventPollerIncomplete) { scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicDictAttack); } @@ -170,8 +171,8 @@ static void nfc_scene_emulate_on_enter_mf_classic(NfcApp* instance) { nfc_listener_start(instance->listener, NULL, NULL); } -static bool nfc_scene_read_menu_on_event_mf_classic(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexDetectReader) { +static bool nfc_scene_read_menu_on_event_mf_classic(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexDetectReader) { scene_manager_next_scene(instance->scene_manager, NfcSceneSaveConfirm); dolphin_deed(DolphinDeedNfcDetectReader); return true; @@ -180,27 +181,29 @@ static bool nfc_scene_read_menu_on_event_mf_classic(NfcApp* instance, uint32_t e return false; } -static bool nfc_scene_saved_menu_on_event_mf_classic(NfcApp* instance, uint32_t event) { +static bool nfc_scene_saved_menu_on_event_mf_classic(NfcApp* instance, SceneManagerEvent event) { bool consumed = false; - if(event == SubmenuIndexDetectReader) { - scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicDetectReader); - consumed = true; - } else if(event == SubmenuIndexWrite) { - scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicWriteInitial); - consumed = true; - } else if(event == SubmenuIndexUpdate) { - scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicUpdateInitial); - consumed = true; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexDetectReader) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicDetectReader); + consumed = true; + } else if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicWriteInitial); + consumed = true; + } else if(event.event == SubmenuIndexUpdate) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicUpdateInitial); + consumed = true; + } } return consumed; } -static bool nfc_scene_save_name_on_event_mf_classic(NfcApp* instance, uint32_t event) { +static bool nfc_scene_save_name_on_event_mf_classic(NfcApp* instance, SceneManagerEvent event) { bool consumed = false; - if(event == NfcCustomEventTextInputDone) { + if(event.type == SceneManagerEventTypeCustom && event.event == NfcCustomEventTextInputDone) { mf_classic_key_cache_save( instance->mfc_key_cache, nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic)); diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 4a8d4d744..662126c02 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -132,15 +132,17 @@ static void nfc_scene_read_on_enter_mf_ultralight(NfcApp* instance) { nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_mf_ultralight, instance); } -bool nfc_scene_read_on_event_mf_ultralight(NfcApp* instance, uint32_t event) { - if(event == NfcCustomEventCardDetected) { - scene_manager_set_scene_state( - instance->scene_manager, NfcSceneRead, NfcSceneMfUltralightReadMenuStateCardFound); - nfc_scene_read_setup_view(instance); - } else if((event == NfcCustomEventPollerIncomplete)) { - notification_message(instance->notifications, &sequence_semi_success); - scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); - dolphin_deed(DolphinDeedNfcReadSuccess); +bool nfc_scene_read_on_event_mf_ultralight(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventCardDetected) { + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneRead, NfcSceneMfUltralightReadMenuStateCardFound); + nfc_scene_read_setup_view(instance); + } else if((event.event == NfcCustomEventPollerIncomplete)) { + notification_message(instance->notifications, &sequence_semi_success); + scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); + } } return true; } @@ -202,14 +204,17 @@ static void nfc_scene_emulate_on_enter_mf_ultralight(NfcApp* instance) { nfc_listener_start(instance->listener, NULL, NULL); } -static bool - nfc_scene_read_and_saved_menu_on_event_mf_ultralight(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexUnlock) { - scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu); - return true; - } else if(event == SubmenuIndexWrite) { - scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrite); - return true; +static bool nfc_scene_read_and_saved_menu_on_event_mf_ultralight( + NfcApp* instance, + SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexUnlock) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu); + return true; + } else if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrite); + return true; + } } return false; } diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index c87ee613f..9bd28b4b7 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -131,10 +131,8 @@ static bool nfc_protocol_support_scene_more_info_on_event(NfcApp* instance, SceneManagerEvent event) { bool consumed = false; - if(event.type == SceneManagerEventTypeCustom) { - const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); - consumed = nfc_protocol_support[protocol]->scene_more_info.on_event(instance, event.event); - } + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + consumed = nfc_protocol_support[protocol]->scene_more_info.on_event(instance, event); return consumed; } @@ -188,8 +186,7 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana } else { const NfcProtocol protocol = instance->protocols_detected[instance->protocols_detected_selected_idx]; - consumed = - nfc_protocol_support[protocol]->scene_read.on_event(instance, event.event); + consumed = nfc_protocol_support[protocol]->scene_read.on_event(instance, event); } } else if(event.event == NfcCustomEventPollerFailure) { nfc_poller_stop(instance->poller); @@ -202,7 +199,7 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana } else if(event.event == NfcCustomEventCardDetected) { const NfcProtocol protocol = instance->protocols_detected[instance->protocols_detected_selected_idx]; - consumed = nfc_protocol_support[protocol]->scene_read.on_event(instance, event.event); + consumed = nfc_protocol_support[protocol]->scene_read.on_event(instance, event); } } else if(event.type == SceneManagerEventTypeBack) { nfc_poller_stop(instance->poller); @@ -287,8 +284,7 @@ static bool consumed = true; } else { const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); - consumed = - nfc_protocol_support[protocol]->scene_read_menu.on_event(instance, event.event); + consumed = nfc_protocol_support[protocol]->scene_read_menu.on_event(instance, event); } } else if(event.type == SceneManagerEventTypeBack) { @@ -456,8 +452,7 @@ static bool consumed = true; } else { const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); - consumed = - nfc_protocol_support[protocol]->scene_saved_menu.on_event(instance, event.event); + consumed = nfc_protocol_support[protocol]->scene_saved_menu.on_event(instance, event); } } else if(event.type == SceneManagerEventTypeBack) { @@ -523,8 +518,8 @@ static bool DolphinDeedNfcSave); const NfcProtocol protocol = instance->protocols_detected[instance->protocols_detected_selected_idx]; - consumed = nfc_protocol_support[protocol]->scene_save_name.on_event( - instance, event.event); + consumed = + nfc_protocol_support[protocol]->scene_save_name.on_event(instance, event); } else { consumed = scene_manager_search_and_switch_to_previous_scene( instance->scene_manager, NfcSceneStart); diff --git a/applications/main/nfc/helpers/protocol_support/slix/slix.c b/applications/main/nfc/helpers/protocol_support/slix/slix.c index ad858a75f..b32776a58 100644 --- a/applications/main/nfc/helpers/protocol_support/slix/slix.c +++ b/applications/main/nfc/helpers/protocol_support/slix/slix.c @@ -91,8 +91,8 @@ static void nfc_scene_emulate_on_enter_slix(NfcApp* instance) { nfc_listener_start(instance->listener, nfc_scene_emulate_listener_callback_slix, instance); } -static bool nfc_scene_saved_menu_on_event_slix(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexCommonEdit) { +static bool nfc_scene_saved_menu_on_event_slix(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexCommonEdit) { scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); return true; } diff --git a/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c b/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c index e22af48b3..e8b31b805 100644 --- a/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c +++ b/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c @@ -60,8 +60,8 @@ static void nfc_scene_read_success_on_enter_st25tb(NfcApp* instance) { furi_string_free(temp_str); } -static bool nfc_scene_saved_menu_on_event_st25tb(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexCommonEdit) { +static bool nfc_scene_saved_menu_on_event_st25tb(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexCommonEdit) { scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); return true; } From aef18f6b2f2ee21a4318893a80f12f7184eb191d Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 23 Jan 2024 22:40:33 +0300 Subject: [PATCH 084/110] Reset widget on exit from more info scene --- .../main/nfc/helpers/protocol_support/nfc_protocol_support.c | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 9bd28b4b7..873863f36 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -139,6 +139,7 @@ static bool static void nfc_protocol_support_scene_more_info_on_exit(NfcApp* instance) { text_box_reset(instance->text_box); + widget_reset(instance->widget); furi_string_reset(instance->text_box_store); } From 2617eccb461a116d7ff4d269134a019cd6c4b189 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 23 Jan 2024 22:41:19 +0300 Subject: [PATCH 085/110] Enum for more info scene states for ultralight cards --- .../helpers/protocol_support/mf_ultralight/mf_ultralight.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 662126c02..711aae0cf 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -15,6 +15,11 @@ enum { SubmenuIndexWrite, }; +enum { + NfcSceneMoreInfoStateASCII, + NfcSceneMoreInfoStateRawData, +}; + static void nfc_scene_info_on_enter_mf_ultralight(NfcApp* instance) { const NfcDevice* device = instance->nfc_device; const MfUltralightData* data = nfc_device_get_data(device, NfcProtocolMfUltralight); From b9498826fd1fbd741ff5ac317bae0618e01d5fa6 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 23 Jan 2024 22:42:19 +0300 Subject: [PATCH 086/110] New implementation of more info logic added --- .../mf_ultralight/mf_ultralight.c | 62 +++++++++++++++++-- .../mf_ultralight/mf_ultralight_render.c | 3 +- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 711aae0cf..cbf7fdf09 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -2,6 +2,7 @@ #include "mf_ultralight_render.h" #include +#include #include "nfc/nfc_app_i.h" @@ -40,11 +41,62 @@ static void nfc_scene_more_info_on_enter_mf_ultralight(NfcApp* instance) { const MfUltralightData* mfu = nfc_device_get_data(device, NfcProtocolMfUltralight); furi_string_reset(instance->text_box_store); - nfc_render_mf_ultralight_dump(mfu, instance->text_box_store); + uint32_t scene_state = + scene_manager_get_scene_state(instance->scene_manager, NfcSceneMoreInfo); - text_box_set_font(instance->text_box, TextBoxFontHex); - text_box_set_text(instance->text_box, furi_string_get_cstr(instance->text_box_store)); - view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewTextBox); + if(scene_state == NfcSceneMoreInfoStateASCII) { + pretty_format_bytes_hex_canonical( + instance->text_box_store, + MF_ULTRALIGHT_PAGE_SIZE, + PRETTY_FORMAT_FONT_MONOSPACE, + (uint8_t*)mfu->page, + mfu->pages_read * MF_ULTRALIGHT_PAGE_SIZE); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 48, furi_string_get_cstr(instance->text_box_store)); + widget_add_button_element( + instance->widget, + GuiButtonTypeRight, + "Raw Data", + nfc_protocol_support_common_widget_callback, + instance); + + widget_add_button_element( + instance->widget, + GuiButtonTypeLeft, + "Info", + nfc_protocol_support_common_widget_callback, + instance); + } else if(scene_state == NfcSceneMoreInfoStateRawData) { + nfc_render_mf_ultralight_dump(mfu, instance->text_box_store); + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 48, furi_string_get_cstr(instance->text_box_store)); + + widget_add_button_element( + instance->widget, + GuiButtonTypeLeft, + "ASCII", + nfc_protocol_support_common_widget_callback, + instance); + } +} + +static bool nfc_scene_more_info_on_event_mf_ultralight(NfcApp* instance, SceneManagerEvent event) { + bool consumed = false; + + if((event.type == SceneManagerEventTypeCustom && event.event == GuiButtonTypeLeft) || + (event.type == SceneManagerEventTypeBack)) { + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneMoreInfo, NfcSceneMoreInfoStateASCII); + scene_manager_previous_scene(instance->scene_manager); + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom && event.event == GuiButtonTypeRight) { + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneMoreInfo, NfcSceneMoreInfoStateRawData); + scene_manager_next_scene(instance->scene_manager, NfcSceneMoreInfo); + consumed = true; + } + return consumed; } static NfcCommand @@ -235,7 +287,7 @@ const NfcProtocolSupportBase nfc_protocol_support_mf_ultralight = { .scene_more_info = { .on_enter = nfc_scene_more_info_on_enter_mf_ultralight, - .on_event = nfc_protocol_support_common_on_event_empty, + .on_event = nfc_scene_more_info_on_event_mf_ultralight, }, .scene_read = { diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c index 5296f4807..1bc508adc 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c @@ -36,10 +36,11 @@ void nfc_render_mf_ultralight_info( } void nfc_render_mf_ultralight_dump(const MfUltralightData* data, FuriString* str) { + furi_string_cat_printf(str, "\e*"); for(size_t i = 0; i < data->pages_read; i++) { const uint8_t* page_data = data->page[i].data; for(size_t j = 0; j < MF_ULTRALIGHT_PAGE_SIZE; j += 2) { - furi_string_cat_printf(str, "%02X%02X ", page_data[j], page_data[j + 1]); + furi_string_cat_printf(str, " %02X%02X", page_data[j], page_data[j + 1]); } } } From eb4d0bb7373a4f8f6121c822b9a0ff93772f70cb Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Tue, 23 Jan 2024 23:01:43 +0300 Subject: [PATCH 087/110] Realigned emulation scene and fixed replaced Mifare to MIFARE --- .../nfc/helpers/protocol_support/nfc_protocol_support.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index fb45f65b9..9c8cad642 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -569,7 +569,7 @@ static void nfc_protocol_support_scene_emulate_on_enter(NfcApp* instance) { if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateUid)) { widget_add_string_element( - widget, 90, 28, AlignCenter, AlignCenter, FontPrimary, "Emulating UID"); + widget, 90, 26, AlignCenter, AlignCenter, FontPrimary, "Emulating UID"); size_t uid_len; const uint8_t* uid = nfc_device_get_uid(instance->nfc_device, &uid_len); @@ -582,7 +582,7 @@ static void nfc_protocol_support_scene_emulate_on_enter(NfcApp* instance) { } else { widget_add_string_element( - widget, 90, 28, AlignCenter, AlignCenter, FontPrimary, "Emulating"); + widget, 90, 26, AlignCenter, AlignCenter, FontPrimary, "Emulating"); if(!furi_string_empty(instance->file_name)) { furi_string_set(temp_str, instance->file_name); } else { @@ -590,11 +590,12 @@ static void nfc_protocol_support_scene_emulate_on_enter(NfcApp* instance) { temp_str, "Unsaved\n%s", nfc_device_get_name(instance->nfc_device, NfcDeviceNameTypeFull)); + furi_string_replace_str(temp_str, "Mifare", "MIFARE"); } } widget_add_text_box_element( - widget, 56, 30, 71, 25, AlignCenter, AlignCenter, furi_string_get_cstr(temp_str), false); + widget, 56, 33, 71, 25, AlignCenter, AlignTop, furi_string_get_cstr(temp_str), false); furi_string_free(temp_str); From 87f8f1d9c450538bd9990a35bbb3e9fd6a9c0773 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Tue, 23 Jan 2024 20:47:17 +0000 Subject: [PATCH 088/110] Remove kostyly, add raw debug --- lib/nfc/helpers/iso14443_4_layer.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/nfc/helpers/iso14443_4_layer.c b/lib/nfc/helpers/iso14443_4_layer.c index 75282c1d6..5b57d918c 100644 --- a/lib/nfc/helpers/iso14443_4_layer.c +++ b/lib/nfc/helpers/iso14443_4_layer.c @@ -3,14 +3,11 @@ #include #define ISO14443_4_BLOCK_PCB (1U << 1) -#define ISO14443_4_BLOCK_PCB_I (0U) -#define ISO14443_4_BLOCK_PCB_R (5U << 5) +#define ISO14443_4_BLOCK_PCB_I (0U << 6) +#define ISO14443_4_BLOCK_PCB_R (2U << 6) #define ISO14443_4_BLOCK_PCB_S (3U << 6) - -//KOSTYLY -#define ISO14443_4_BLOCK_PCB_I_ (0U << 6) -#define ISO14443_4_BLOCK_PCB_R_ (2U << 6) #define ISO14443_4_BLOCK_PCB_TYPE_MASK (3U << 6) + #define ISO14443_4_BLOCK_PCB_S_DESELECT (0U << 4) #define ISO14443_4_BLOCK_PCB_S_WTX (3U << 4) #define ISO14443_4_BLOCK_PCB_BLOCK_NUMBER (1U << 0) @@ -87,7 +84,7 @@ Iso14443_4aError iso14443_4_layer_decode_block_pwt_ext( const uint8_t pcb_field = bit_buffer_get_byte(block_data, 0); const uint8_t block_type = pcb_field & ISO14443_4_BLOCK_PCB_TYPE_MASK; switch(block_type) { - case ISO14443_4_BLOCK_PCB_I_: + case ISO14443_4_BLOCK_PCB_I: if(pcb_field == instance->pcb_prev) { bit_buffer_copy_right(output_data, block_data, 1); ret = Iso14443_4aErrorNone; @@ -96,7 +93,7 @@ Iso14443_4aError iso14443_4_layer_decode_block_pwt_ext( ret = Iso14443_4aErrorProtocol; } break; - case ISO14443_4_BLOCK_PCB_R_: + case ISO14443_4_BLOCK_PCB_R: // TODO break; case ISO14443_4_BLOCK_PCB_S: @@ -117,5 +114,13 @@ Iso14443_4aError iso14443_4_layer_decode_block_pwt_ext( } } while(false); + if(ret != Iso14443_4aErrorNone) { + FURI_LOG_RAW_T("RAW RX:"); + for(size_t x = 0; x < bit_buffer_get_size_bytes(block_data); x++) { + FURI_LOG_RAW_T("%02X ", bit_buffer_get_byte(block_data, x)); + } + FURI_LOG_RAW_T("\r\n"); + } + return ret; -} \ No newline at end of file +} From 3f6092d95c2d6dc407da0077b544673ee8ef11d4 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Tue, 23 Jan 2024 21:03:54 +0000 Subject: [PATCH 089/110] Don't stop if SELECT APPLICATION failed --- lib/nfc/protocols/emv/emv_poller.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c index 41ae8afba..e26c4e137 100644 --- a/lib/nfc/protocols/emv/emv_poller.c +++ b/lib/nfc/protocols/emv/emv_poller.c @@ -82,11 +82,11 @@ static NfcCommand emv_poller_handler_select_application(EmvPoller* instance) { if(instance->error == EmvErrorNone) { FURI_LOG_D(TAG, "Select application success"); - instance->state = EmvPollerStateGetProcessingOptions; } else { FURI_LOG_E(TAG, "Failed to select application"); - instance->state = EmvPollerStateReadFailed; + // We have to try GPO request with empty tag } + instance->state = EmvPollerStateGetProcessingOptions; return NfcCommandContinue; } From 3fce83eb79b1088f5540cac5cf4a6b73781453c0 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Tue, 23 Jan 2024 21:34:39 +0000 Subject: [PATCH 090/110] Process error codes --- lib/nfc/protocols/emv/emv.h | 3 ++- lib/nfc/protocols/emv/emv_poller_i.c | 23 ++++++++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index c7463ab98..699a0eca1 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -24,9 +24,10 @@ extern "C" { #define EMV_TAG_CURRENCY_CODE 0x9F42 #define EMV_TAG_CARDHOLDER_NAME 0x5F20 #define EMV_TAG_TRACK_2_DATA 0x9F6B +#define EMV_TAG_GPO_FMT1 0x80 #define EMV_TAG_RESP_BUF_SIZE 0x6C -#define EMV_TAG_GPO_FMT1 0x80 +#define EMV_TAG_RESP_BYTES_AVAILABLE 0x61 typedef struct { uint16_t tag; diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 2b9bdc6e0..a2353b52a 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -117,6 +117,24 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio while(i < len) { first_byte = buff[i]; + + if((len == 2) && ((first_byte >> 4) == 6)) { + switch(buff[i]) { + case EMV_TAG_RESP_BUF_SIZE: + FURI_LOG_T(TAG, " Wrong length. Read %02X bytes", buff[i + 1]); + // Need to request SFI again with this length value + return success; + case EMV_TAG_RESP_BYTES_AVAILABLE: + FURI_LOG_T(TAG, " Bytes available: %02X", buff[i + 1]); + // Need to request one more time + return success; + + default: + FURI_LOG_T(TAG, " Error/warning code: %02X %02X", buff[i], buff[i + 1]); + return success; + } + } + if((first_byte & 31) == 31) { // 2-byte tag tag = buff[i] << 8 | buff[i + 1]; i++; @@ -154,11 +172,6 @@ static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplicatio success = true; FURI_LOG_T(TAG, "found EMV_TAG_GPO_FMT1 %X: ", tag); break; - case EMV_TAG_RESP_BUF_SIZE: - //success = true; - FURI_LOG_T(TAG, "found EMV_TAG_RESP_BUF_SIZE %X: %d", tag, buff[i]); - // Need to request SFI again with this length value - break; case EMV_TAG_AID: app->aid_len = tlen; memcpy(app->aid, &buff[i], tlen); From 5e384ccc4348c6f538eb5e9e21f6df58f0157d10 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Tue, 23 Jan 2024 21:54:32 +0000 Subject: [PATCH 091/110] Fix log --- lib/nfc/protocols/emv/emv_poller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c index e26c4e137..25d3e0507 100644 --- a/lib/nfc/protocols/emv/emv_poller.c +++ b/lib/nfc/protocols/emv/emv_poller.c @@ -99,7 +99,7 @@ static NfcCommand emv_poller_handler_get_processing_options(EmvPoller* instance) if(instance->data->emv_application.pan_len > 0) { instance->state = EmvPollerStateReadSuccess; } else { - FURI_LOG_D(TAG, "No AFL still. Fallback to bruteforce files"); + FURI_LOG_D(TAG, "No PAN still. Read SFI files"); instance->state = EmvPollerStateReadFiles; } } else { From c014491f55113c90d6d3d4439b9a598dc9c9293e Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Tue, 23 Jan 2024 22:03:02 +0000 Subject: [PATCH 092/110] Support 19 bytes PAN (eg.MIR virt) --- applications/main/nfc/plugins/supported_cards/emv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index 703a98cb6..f870b6393 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -896,6 +896,10 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { furi_string_cat_printf(parsed_data, "%02X", app.pan[i]); } + // Cut padding 'F' from card number + size_t end = furi_string_search_rchar(parsed_data, 'F'); + if(end) furi_string_left(parsed_data, end); + furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X", app.exp_month, app.exp_year); furi_string_cat_printf(parsed_data, "\nCountry: %s", get_country_name(app.country_code)); From 1e6fe92b4417ff9c3553707abbb4a9e7ab608cfa Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 24 Jan 2024 21:51:31 +0300 Subject: [PATCH 093/110] nfc_protocol_support_has_feature is now public --- .../main/nfc/helpers/protocol_support/nfc_protocol_support.c | 2 +- .../main/nfc/helpers/protocol_support/nfc_protocol_support.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index c87ee613f..b80553ae4 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -74,7 +74,7 @@ void nfc_protocol_support_on_exit(NfcProtocolSupportScene scene, void* context) nfc_protocol_support_scenes[scene].on_exit(instance); } -static bool nfc_protocol_support_has_feature(NfcProtocol protocol, NfcProtocolFeature feature) { +bool nfc_protocol_support_has_feature(NfcProtocol protocol, NfcProtocolFeature feature) { return nfc_protocol_support[protocol]->features & feature; } diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h index b6bfde45c..855642c62 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h @@ -76,6 +76,7 @@ #pragma once #include +#include #include "nfc_protocol_support_common.h" @@ -111,3 +112,5 @@ bool nfc_protocol_support_on_event( * @param[in,out] context pointer to a user-specified context (will be passed to concrete handler). */ void nfc_protocol_support_on_exit(NfcProtocolSupportScene scene, void* context); + +bool nfc_protocol_support_has_feature(NfcProtocol protocol, NfcProtocolFeature feature); \ No newline at end of file From 63eeb86bc7a6afc9e9060736cefe184b82169cd6 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Wed, 24 Jan 2024 21:52:24 +0300 Subject: [PATCH 094/110] Added function to show different scene depending on supported features of the device --- applications/main/nfc/nfc_app.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 183f49895..f8ff11239 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -1,4 +1,5 @@ #include "nfc_app_i.h" +#include "helpers/protocol_support/nfc_protocol_support.h" #include @@ -466,6 +467,15 @@ static bool nfc_is_hal_ready() { } } +static void nfc_show_initial_scene_for_device(NfcApp* nfc) { + NfcProtocol prot = nfc_device_get_protocol(nfc->nfc_device); + uint32_t scene = nfc_protocol_support_has_feature( + prot, NfcProtocolFeatureEmulateFull | NfcProtocolFeatureEmulateUid) ? + NfcSceneEmulate : + NfcSceneSavedMenu; + scene_manager_next_scene(nfc->scene_manager, scene); +} + int32_t nfc_app(void* p) { if(!nfc_is_hal_ready()) return 0; @@ -485,7 +495,7 @@ int32_t nfc_app(void* p) { furi_string_set(nfc->file_path, args); if(nfc_load_file(nfc, nfc->file_path, false)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulate); + nfc_show_initial_scene_for_device(nfc); } else { view_dispatcher_stop(nfc->view_dispatcher); } From 7a89789a289651269bc6208b393a8b7a43ba89e5 Mon Sep 17 00:00:00 2001 From: RebornedBrain Date: Thu, 25 Jan 2024 15:02:19 +0300 Subject: [PATCH 095/110] Check simplified --- .../helpers/protocol_support/nfc_protocol_support_gui_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c index 620fd48ff..8c38f8475 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c @@ -38,5 +38,5 @@ void nfc_protocol_support_common_on_enter_empty(NfcApp* instance) { bool nfc_protocol_support_common_on_event_empty(NfcApp* instance, SceneManagerEvent event) { UNUSED(instance); UNUSED(event); - return event.type != SceneManagerEventTypeBack ? true : false; + return event.type != SceneManagerEventTypeBack; } From 39055ff701307863a29223ce179ac6a3fafdeecc Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Sat, 27 Jan 2024 22:43:01 +0000 Subject: [PATCH 096/110] Improve info screen * search F only in card_number --- .../helpers/protocol_support/emv/emv_render.c | 1 + .../main/nfc/plugins/supported_cards/emv.c | 24 ++++++++----------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c index ead426a15..7727816cc 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -17,6 +17,7 @@ void nfc_render_emv_data(const EmvData* data, FuriString* str) { void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str) { if(len == 0) return; + furi_string_cat_printf(str, "PAN: "); for(uint8_t i = 0; i < len; i += 2) { furi_string_cat_printf(str, "%02X%02X ", data[i], data[i + 1]); } diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index f870b6393..09eb804e5 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -886,30 +886,26 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { do { if(app.name_found) - furi_string_cat_printf(parsed_data, "\e#%s", app.name); + furi_string_cat_printf(parsed_data, "\e#%s\n", app.name); else - furi_string_cat_printf(parsed_data, "\e#%s", "EMV"); + furi_string_cat_printf(parsed_data, "\e#%s\n", "EMV"); - furi_string_cat_printf(parsed_data, "\nPAN:"); - for(uint8_t i = 0; i < app.pan_len; i++) { - if((i % 2 == 0)) furi_string_cat_printf(parsed_data, " "); - furi_string_cat_printf(parsed_data, "%02X", app.pan[i]); + FuriString* card_number = furi_string_alloc(); + for(uint8_t i = 0; i < app.pan_len; i += 2) { + furi_string_cat_printf(card_number, "%02X%02X ", app.pan[i], app.pan[i + 1]); } // Cut padding 'F' from card number - size_t end = furi_string_search_rchar(parsed_data, 'F'); - if(end) furi_string_left(parsed_data, end); + size_t end = furi_string_search_rchar(card_number, 'F'); + if(end) furi_string_left(card_number, end); + furi_string_cat(parsed_data, card_number); + furi_string_free(card_number); furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X", app.exp_month, app.exp_year); furi_string_cat_printf(parsed_data, "\nCountry: %s", get_country_name(app.country_code)); - furi_string_cat_printf( - parsed_data, "\nCurrency: %s", get_currency_name(app.currency_code)); - - furi_string_cat_printf(parsed_data, "\nAID: "); - for(uint8_t i = 0; i < app.aid_len; i++) - furi_string_cat_printf(parsed_data, "%02X", app.aid[i]); + parsed_data, " Currency: %s", get_currency_name(app.currency_code)); parsed = true; } while(false); From 4b786fb77e2e5c353e4de84184699376aaca267a Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Sun, 28 Jan 2024 03:57:12 +0000 Subject: [PATCH 097/110] Refactor response decoder Read transactions history --- .../helpers/protocol_support/emv/emv_render.c | 50 ++ .../helpers/protocol_support/emv/emv_render.h | 2 + lib/nfc/protocols/emv/emv.h | 22 + lib/nfc/protocols/emv/emv_poller.c | 21 +- lib/nfc/protocols/emv/emv_poller.h | 4 +- lib/nfc/protocols/emv/emv_poller_i.c | 526 ++++++++++++------ lib/nfc/protocols/emv/emv_poller_i.h | 1 + targets/f7/api_symbols.csv | 5 +- 8 files changed, 451 insertions(+), 180 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c index 7727816cc..10333a936 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -60,6 +60,56 @@ void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { furi_string_cat_printf(str, "\n"); } +void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { + const uint8_t len = apl->active_tr; + if(!len) { + return; + } + furi_string_cat_printf(str, "Transactions:\n"); + for(int i = 0; i < len; i++) { + if(!apl->trans[i].amount) continue; + uint8_t* a = (uint8_t*)&apl->trans[i].amount; + furi_string_cat_printf(str, "%d: ", apl->trans[i].atc); + bool top = true; + for(int x = 0; x < 6; x++) { + if(x == 5) { + furi_string_cat_printf(str, ".%02X", a[x]); + break; + } + if(a[x]) { + if(top) { + furi_string_cat_printf(str, "%X", a[x]); + top = false; + } else { + furi_string_cat_printf(str, "%02X", a[x]); + } + } + } + // TODO to string + furi_string_cat_printf(str, " %x\n", apl->trans[i].currency); + + // TODO to string + if(apl->trans[i].country) + furi_string_cat_printf(str, "country: %x\n", apl->trans[i].country); + + if(apl->trans[i].time) + furi_string_cat_printf( + str, + "%02lx:%02lx:%02lx ", + apl->trans[i].time & 0xff, + (apl->trans[i].time >> 8) & 0xff, + apl->trans[i].time >> 16); + if(apl->trans[i].date) + furi_string_cat_printf( + str, + "%02lx/%02lx/%02lx\n", + apl->trans[i].date >> 16, + (apl->trans[i].date >> 8) & 0xff, + apl->trans[i].date & 0xff); + } +} + void nfc_render_emv_extra(const EmvData* data, FuriString* str) { nfc_render_emv_application(&data->emv_application, str); + //nfc_render_emv_transactions(&data->emv_application, str); } diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h index 8fb31eaea..fd73cfc6b 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h @@ -22,3 +22,5 @@ void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str); void nfc_render_emv_country(const EmvApplication* apl, FuriString* str); void nfc_render_emv_currency(const EmvApplication* apl, FuriString* str); + +void nfc_render_emv_transactions(const EmvApplication* data, FuriString* str); \ No newline at end of file diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index 699a0eca1..b565ee334 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -15,6 +15,15 @@ extern "C" { #define EMV_TAG_CARD_NAME 0x50 #define EMV_TAG_FCI 0xBF0C #define EMV_TAG_LOG_ENTRY 0x9F4D +#define EMV_TAG_LOG_FMT 0x9F4F + +#define EMV_TAG_ATC 0x9F36 +#define EMV_TAG_LOG_AMOUNT 0x9F02 +#define EMV_TAG_LOG_COUNTRY 0x9F1A +#define EMV_TAG_LOG_CURRENCY 0x5F2A +#define EMV_TAG_LOG_DATE 0x9A +#define EMV_TAG_LOG_TIME 0x9F21 + #define EMV_TAG_TRACK_1_EQUIV 0x56 #define EMV_TAG_TRACK_2_EQUIV 0x57 #define EMV_TAG_PAN 0x5A @@ -39,9 +48,22 @@ typedef struct { uint8_t data[MAX_APDU_LEN]; } APDU; +typedef struct { + uint16_t atc; + uint64_t amount; + uint16_t country; + uint16_t currency; + uint32_t date; + uint32_t time; +} Transaction; + typedef struct { uint8_t log_sfi; uint8_t log_records; + uint8_t log_fmt[50]; + uint8_t log_fmt_len; + uint8_t active_tr; + Transaction trans[16]; uint8_t priority; uint8_t aid[16]; uint8_t aid_len; diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c index 25d3e0507..70051afcd 100644 --- a/lib/nfc/protocols/emv/emv_poller.c +++ b/lib/nfc/protocols/emv/emv_poller.c @@ -111,11 +111,14 @@ static NfcCommand emv_poller_handler_get_processing_options(EmvPoller* instance) } static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) { - instance->error = emv_poller_read_files(instance); + instance->error = emv_poller_read_afl(instance); if(instance->error == EmvErrorNone) { FURI_LOG_D(TAG, "Read files success"); - instance->state = EmvPollerStateReadSuccess; + if(instance->data->emv_application.log_sfi) + instance->state = EmvPollerStateReadLogs; + else + instance->state = EmvPollerStateReadSuccess; } else { FURI_LOG_E(TAG, "Failed to read files"); instance->state = EmvPollerStateReadFailed; @@ -124,6 +127,19 @@ static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) { return NfcCommandContinue; } +static NfcCommand emv_poller_handler_read_logs(EmvPoller* instance) { + instance->error = emv_poller_read_log_entry(instance); + + if(instance->error == EmvErrorNone) { + FURI_LOG_D(TAG, "Log entries had been read"); + } else { + FURI_LOG_D(TAG, "No log entry"); + } + + instance->state = EmvPollerStateReadSuccess; + return NfcCommandContinue; +} + static NfcCommand emv_poller_handler_read_fail(EmvPoller* instance) { FURI_LOG_D(TAG, "Read failed"); iso14443_4a_poller_halt(instance->iso14443_4a_poller); @@ -147,6 +163,7 @@ static const EmvPollerReadHandler emv_poller_read_handler[EmvPollerStateNum] = { [EmvPollerStateSelectApplication] = emv_poller_handler_select_application, [EmvPollerStateGetProcessingOptions] = emv_poller_handler_get_processing_options, [EmvPollerStateReadFiles] = emv_poller_handler_read_files, + [EmvPollerStateReadLogs] = emv_poller_handler_read_logs, [EmvPollerStateReadFailed] = emv_poller_handler_read_fail, [EmvPollerStateReadSuccess] = emv_poller_handler_read_success, }; diff --git a/lib/nfc/protocols/emv/emv_poller.h b/lib/nfc/protocols/emv/emv_poller.h index 36f27578a..c2335bfa4 100644 --- a/lib/nfc/protocols/emv/emv_poller.h +++ b/lib/nfc/protocols/emv/emv_poller.h @@ -46,7 +46,9 @@ EmvError emv_poller_get_processing_options(EmvPoller* instance); EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t record_num); -EmvError emv_poller_read_files(EmvPoller* instance); +EmvError emv_poller_read_afl(EmvPoller* instance); + +EmvError emv_poller_read_log_entry(EmvPoller* instance); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index a2353b52a..eb27786cc 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -109,179 +109,277 @@ static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) { return dest->size; } -static bool emv_decode_response(const uint8_t* buff, uint16_t len, EmvApplication* app) { - uint16_t i = 0; - uint16_t tag = 0, first_byte = 0; - uint16_t tlen = 0; +static bool + emv_decode_tlv_tag(const uint8_t* buff, uint16_t tag, uint8_t tlen, EmvApplication* app) { + uint8_t i = 0; + bool success = false; + + switch(tag) { + case EMV_TAG_LOG_FMT: + furi_check(tlen < sizeof(app->log_fmt)); + memcpy(app->log_fmt, &buff[i], tlen); + app->log_fmt_len = tlen; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_LOG_FMT %X: len %d", tag, tlen); + break; + case EMV_TAG_GPO_FMT1: + // skip AIP + i += 2; + tlen -= 2; + furi_check(tlen < sizeof(app->afl.data)); + memcpy(app->afl.data, &buff[i], tlen); + app->afl.size = tlen; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_GPO_FMT1 %X: ", tag); + break; + case EMV_TAG_AID: + app->aid_len = tlen; + memcpy(app->aid, &buff[i], tlen); + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_AID %X: ", tag); + for(size_t x = 0; x < tlen; x++) { + FURI_LOG_RAW_T("%02X ", app->aid[x]); + } + FURI_LOG_RAW_T("\r\n"); + break; + case EMV_TAG_PRIORITY: + memcpy(&app->priority, &buff[i], tlen); + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_APP_PRIORITY %X: %d", tag, app->priority); + break; + case EMV_TAG_CARD_NAME: + memcpy(app->name, &buff[i], tlen); + app->name[tlen] = '\0'; + app->name_found = true; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_CARD_NAME %x : %s", tag, app->name); + break; + case EMV_TAG_PDOL: + memcpy(app->pdol.data, &buff[i], tlen); + app->pdol.size = tlen; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_PDOL %x (len=%d)", tag, tlen); + break; + case EMV_TAG_AFL: + memcpy(app->afl.data, &buff[i], tlen); + app->afl.size = tlen; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_AFL %x (len=%d)", tag, tlen); + break; + // Tracks data https://murdoch.is/papers/defcon20emvdecode.pdf + case EMV_TAG_TRACK_1_EQUIV: { + // Contain PAN and expire date + char track_1_equiv[80]; + memcpy(track_1_equiv, &buff[i], tlen); + track_1_equiv[tlen] = '\0'; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_1_EQUIV %x : %s", tag, track_1_equiv); + break; + } + case EMV_TAG_TRACK_2_DATA: + case EMV_TAG_TRACK_2_EQUIV: { + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2 %X", tag); + // 0xD0 delimits PAN from expiry (YYMM) + for(int x = 1; x < tlen; x++) { + if(buff[i + x + 1] > 0xD0) { + memcpy(app->pan, &buff[i], x + 1); + app->pan_len = x + 1; + app->exp_year = (buff[i + x + 1] << 4) | (buff[i + x + 2] >> 4); + app->exp_month = (buff[i + x + 2] << 4) | (buff[i + x + 3] >> 4); + break; + } + } + + // Convert 4-bit to ASCII representation + char track_2_equiv[41]; + uint8_t track_2_equiv_len = 0; + for(int x = 0; x < tlen; x++) { + char top = (buff[i + x] >> 4) + '0'; + char bottom = (buff[i + x] & 0x0F) + '0'; + track_2_equiv[x * 2] = top; + track_2_equiv_len++; + if(top == '?') break; + track_2_equiv[x * 2 + 1] = bottom; + track_2_equiv_len++; + if(bottom == '?') break; + } + track_2_equiv[track_2_equiv_len] = '\0'; + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2 %X : %s", tag, track_2_equiv); + success = true; + break; + } + case EMV_TAG_PAN: + memcpy(app->pan, &buff[i], tlen); + app->pan_len = tlen; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_PAN %x", tag); + break; + case EMV_TAG_EXP_DATE: + app->exp_year = buff[i]; + app->exp_month = buff[i + 1]; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_EXP_DATE %x", tag); + break; + case EMV_TAG_CURRENCY_CODE: + app->currency_code = (buff[i] << 8 | buff[i + 1]); + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_CURRENCY_CODE %x", tag); + break; + case EMV_TAG_COUNTRY_CODE: + app->country_code = (buff[i] << 8 | buff[i + 1]); + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_COUNTRY_CODE %x", tag); + break; + case EMV_TAG_LOG_ENTRY: + app->log_sfi = buff[i]; + app->log_records = buff[i + 1]; + success = true; + FURI_LOG_T( + TAG, + "found EMV_TAG_LOG_ENTRY %x: sfi 0x%x, records %d", + tag, + app->log_sfi, + app->log_records); + break; + case EMV_TAG_ATC: + app->trans[app->active_tr].atc = (buff[i] << 8 | buff[i + 1]); + success = true; + break; + case EMV_TAG_LOG_AMOUNT: + memcpy(&app->trans[app->active_tr].amount, &buff[i], tlen); + success = true; + break; + case EMV_TAG_LOG_COUNTRY: + app->trans[app->active_tr].country = (buff[i] << 8 | buff[i + 1]); + success = true; + break; + case EMV_TAG_LOG_CURRENCY: + app->trans[app->active_tr].currency = (buff[i] << 8 | buff[i + 1]); + success = true; + break; + case EMV_TAG_LOG_DATE: + memcpy(&app->trans[app->active_tr].date, &buff[i], tlen); + success = true; + break; + case EMV_TAG_LOG_TIME: + memcpy(&app->trans[app->active_tr].time, &buff[i], tlen); + success = true; + break; + } + return success; +} + +static bool emv_response_error(const uint8_t* buff, uint16_t len) { + uint8_t i = 0; + uint8_t first_byte = 0; + bool error = true; + + first_byte = buff[i]; + + if((len == 2) && ((first_byte >> 4) == 6)) { + switch(buff[i]) { + case EMV_TAG_RESP_BUF_SIZE: + FURI_LOG_T(TAG, " Wrong length. Read %02X bytes", buff[i + 1]); + // Need to request SFI again with this length value + return error; + case EMV_TAG_RESP_BYTES_AVAILABLE: + FURI_LOG_T(TAG, " Bytes available: %02X", buff[i + 1]); + // Need to request one more time + return error; + + default: + FURI_LOG_T(TAG, " Error/warning code: %02X %02X", buff[i], buff[i + 1]); + return error; + } + } + return false; +} + +static bool + emv_parse_tag(const uint8_t* buff, uint16_t len, uint16_t* t, uint8_t* tl, uint8_t* off) { + uint8_t i = *off; + uint16_t tag = 0; + uint8_t first_byte = 0; + uint8_t tlen = 0; + bool success = false; + + first_byte = buff[i]; + + if(emv_response_error(buff, len)) return success; + + if((first_byte & 31) == 31) { // 2-byte tag + tag = buff[i] << 8 | buff[i + 1]; + i++; + FURI_LOG_T(TAG, " 2-byte TLV EMV tag: %x", tag); + } else { + tag = buff[i]; + FURI_LOG_T(TAG, " 1-byte TLV EMV tag: %x", tag); + } + i++; + tlen = buff[i]; + if((tlen & 128) == 128) { // long length value + i++; + tlen = buff[i]; + FURI_LOG_T(TAG, " 2-byte TLV length: %d", tlen); + } else { + FURI_LOG_T(TAG, " 1-byte TLV length: %d", tlen); + } + i++; + + *off = i; + *t = tag; + *tl = tlen; + success = true; + return success; +} + +static bool emv_decode_tl( + const uint8_t* buff, + uint16_t len, + const uint8_t* fmt, + uint8_t fmt_len, + EmvApplication* app) { + uint8_t i = 0; + uint8_t f = 0; + uint16_t tag = 0; + uint8_t tlen = 0; + bool success = false; + + if(emv_response_error(buff, len)) return success; + + while(f < fmt_len && i < len) { + success = emv_parse_tag(fmt, fmt_len, &tag, &tlen, &f); + if(!success) return success; + emv_decode_tlv_tag(&buff[i], tag, tlen, app); + i += tlen; + } + success = true; + return success; +} + +static bool emv_decode_response_tlv(const uint8_t* buff, uint8_t len, EmvApplication* app) { + uint8_t i = 0; + uint16_t tag = 0; + uint8_t first_byte = 0; + uint8_t tlen = 0; bool success = false; while(i < len) { first_byte = buff[i]; - if((len == 2) && ((first_byte >> 4) == 6)) { - switch(buff[i]) { - case EMV_TAG_RESP_BUF_SIZE: - FURI_LOG_T(TAG, " Wrong length. Read %02X bytes", buff[i + 1]); - // Need to request SFI again with this length value - return success; - case EMV_TAG_RESP_BYTES_AVAILABLE: - FURI_LOG_T(TAG, " Bytes available: %02X", buff[i + 1]); - // Need to request one more time - return success; + success = emv_parse_tag(buff, len, &tag, &tlen, &i); + if(!success) return success; - default: - FURI_LOG_T(TAG, " Error/warning code: %02X %02X", buff[i], buff[i + 1]); - return success; - } - } - - if((first_byte & 31) == 31) { // 2-byte tag - tag = buff[i] << 8 | buff[i + 1]; - i++; - FURI_LOG_T(TAG, " 2-byte TLV EMV tag: %x", tag); - } else { - tag = buff[i]; - FURI_LOG_T(TAG, " 1-byte TLV EMV tag: %x", tag); - } - i++; - tlen = buff[i]; - if((tlen & 128) == 128) { // long length value - i++; - tlen = buff[i]; - FURI_LOG_T(TAG, " 2-byte TLV length: %d", tlen); - } else { - FURI_LOG_T(TAG, " 1-byte TLV length: %d", tlen); - } - i++; if((first_byte & 32) == 32) { // "Constructed" -- contains more TLV data to parse FURI_LOG_T(TAG, "Constructed TLV %x", tag); - if(!emv_decode_response(&buff[i], tlen, app)) { + if(!emv_decode_response_tlv(&buff[i], tlen, app)) { FURI_LOG_T(TAG, "Failed to decode response for %x", tag); // return false; } else { success = true; } } else { - switch(tag) { - case EMV_TAG_GPO_FMT1: - // skip AIP - i += 2; - tlen -= 2; - memcpy(app->afl.data, &buff[i], tlen); - app->afl.size = tlen; - success = true; - FURI_LOG_T(TAG, "found EMV_TAG_GPO_FMT1 %X: ", tag); - break; - case EMV_TAG_AID: - app->aid_len = tlen; - memcpy(app->aid, &buff[i], tlen); - success = true; - FURI_LOG_T(TAG, "found EMV_TAG_AID %X: ", tag); - for(size_t x = 0; x < tlen; x++) { - FURI_LOG_RAW_T("%02X ", app->aid[x]); - } - FURI_LOG_RAW_T("\r\n"); - break; - case EMV_TAG_PRIORITY: - memcpy(&app->priority, &buff[i], tlen); - success = true; - FURI_LOG_T(TAG, "found EMV_TAG_APP_PRIORITY %X: %d", tag, app->priority); - break; - case EMV_TAG_CARD_NAME: - memcpy(app->name, &buff[i], tlen); - app->name[tlen] = '\0'; - app->name_found = true; - success = true; - FURI_LOG_T(TAG, "found EMV_TAG_CARD_NAME %x : %s", tag, app->name); - break; - case EMV_TAG_PDOL: - memcpy(app->pdol.data, &buff[i], tlen); - app->pdol.size = tlen; - success = true; - FURI_LOG_T(TAG, "found EMV_TAG_PDOL %x (len=%d)", tag, tlen); - break; - case EMV_TAG_AFL: - memcpy(app->afl.data, &buff[i], tlen); - app->afl.size = tlen; - success = true; - FURI_LOG_T(TAG, "found EMV_TAG_AFL %x (len=%d)", tag, tlen); - break; - // Tracks data https://murdoch.is/papers/defcon20emvdecode.pdf - case EMV_TAG_TRACK_1_EQUIV: { - // Contain PAN and expire date - char track_1_equiv[80]; - memcpy(track_1_equiv, &buff[i], tlen); - track_1_equiv[tlen] = '\0'; - success = true; - FURI_LOG_T(TAG, "found EMV_TAG_TRACK_1_EQUIV %x : %s", tag, track_1_equiv); - break; - } - case EMV_TAG_TRACK_2_DATA: - case EMV_TAG_TRACK_2_EQUIV: { - FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2 %X", tag); - // 0xD0 delimits PAN from expiry (YYMM) - for(int x = 1; x < tlen; x++) { - if(buff[i + x + 1] > 0xD0) { - memcpy(app->pan, &buff[i], x + 1); - app->pan_len = x + 1; - app->exp_year = (buff[i + x + 1] << 4) | (buff[i + x + 2] >> 4); - app->exp_month = (buff[i + x + 2] << 4) | (buff[i + x + 3] >> 4); - break; - } - } - - // Convert 4-bit to ASCII representation - char track_2_equiv[41]; - uint8_t track_2_equiv_len = 0; - for(int x = 0; x < tlen; x++) { - char top = (buff[i + x] >> 4) + '0'; - char bottom = (buff[i + x] & 0x0F) + '0'; - track_2_equiv[x * 2] = top; - track_2_equiv_len++; - if(top == '?') break; - track_2_equiv[x * 2 + 1] = bottom; - track_2_equiv_len++; - if(bottom == '?') break; - } - track_2_equiv[track_2_equiv_len] = '\0'; - FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2 %X : %s", tag, track_2_equiv); - success = true; - break; - } - case EMV_TAG_PAN: - memcpy(app->pan, &buff[i], tlen); - app->pan_len = tlen; - success = true; - FURI_LOG_T(TAG, "found EMV_TAG_PAN %x", tag); - break; - case EMV_TAG_EXP_DATE: - app->exp_year = buff[i]; - app->exp_month = buff[i + 1]; - success = true; - FURI_LOG_T(TAG, "found EMV_TAG_EXP_DATE %x", tag); - break; - case EMV_TAG_CURRENCY_CODE: - app->currency_code = (buff[i] << 8 | buff[i + 1]); - success = true; - FURI_LOG_T(TAG, "found EMV_TAG_CURRENCY_CODE %x", tag); - break; - case EMV_TAG_COUNTRY_CODE: - app->country_code = (buff[i] << 8 | buff[i + 1]); - success = true; - FURI_LOG_T(TAG, "found EMV_TAG_COUNTRY_CODE %x", tag); - break; - case EMV_TAG_LOG_ENTRY: - app->log_sfi = buff[i]; - app->log_records = buff[i + 1]; - success = true; - FURI_LOG_T( - TAG, - "found EMV_TAG_LOG_ENTRY %x: sfi 0x%x, records %d", - tag, - app->log_sfi, - app->log_records); - break; - } + emv_decode_tlv_tag(&buff[i], tag, tlen, app); } i += tlen; } @@ -320,7 +418,7 @@ EmvError emv_poller_select_ppse(EmvPoller* instance) { const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); - if(!emv_decode_response( + if(!emv_decode_response_tlv( buff, bit_buffer_get_size_bytes(instance->rx_buffer), &instance->data->emv_application)) { @@ -372,7 +470,7 @@ EmvError emv_poller_select_application(EmvPoller* instance) { const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); - if(!emv_decode_response( + if(!emv_decode_response_tlv( buff, bit_buffer_get_size_bytes(instance->rx_buffer), &instance->data->emv_application)) { @@ -424,7 +522,7 @@ EmvError emv_poller_get_processing_options(EmvPoller* instance) { const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); - if(!emv_decode_response( + if(!emv_decode_response_tlv( buff, bit_buffer_get_size_bytes(instance->rx_buffer), &instance->data->emv_application)) { @@ -466,17 +564,6 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re error = emv_process_error(iso14443_4a_error); break; } - - const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); - - if(!emv_decode_response( - buff, - bit_buffer_get_size_bytes(instance->rx_buffer), - &instance->data->emv_application)) { - // It's ok while bruteforcing - //error = EmvErrorProtocol; - FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record_num); - } } while(false); furi_string_free(text); @@ -484,7 +571,7 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re return error; } -EmvError emv_poller_read_files(EmvPoller* instance) { +EmvError emv_poller_read_afl(EmvPoller* instance) { EmvError error = EmvErrorNone; APDU* afl = &instance->data->emv_application.afl; @@ -504,6 +591,14 @@ EmvError emv_poller_read_files(EmvPoller* instance) { for(uint8_t record = record_start; record <= record_end; ++record) { error = emv_poller_read_sfi_record(instance, sfi, record); if(error != EmvErrorNone) break; + + if(!emv_decode_response_tlv( + bit_buffer_get_data(instance->rx_buffer), + bit_buffer_get_size_bytes(instance->rx_buffer), + &instance->data->emv_application)) { + error = EmvErrorProtocol; + FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record); + } if(instance->data->emv_application.pan_len != 0) return EmvErrorNone; // Card number fetched } @@ -511,4 +606,85 @@ EmvError emv_poller_read_files(EmvPoller* instance) { } return error; -} \ No newline at end of file +} + +static EmvError emv_poller_get_log_format(EmvPoller* instance) { + EmvError error = EmvErrorNone; + + const uint8_t cla_ins[] = {0x80, 0xCA}; + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + bit_buffer_copy_bytes(instance->tx_buffer, cla_ins, sizeof(cla_ins)); + bit_buffer_append_byte(instance->tx_buffer, EMV_TAG_LOG_FMT >> 8); + bit_buffer_append_byte(instance->tx_buffer, EMV_TAG_LOG_FMT & 0xFF); + bit_buffer_append_byte(instance->tx_buffer, 0x00); //Length + + do { + FURI_LOG_D(TAG, "Get log format"); + + Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block_pwt_ext( + instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); + + emv_trace(instance, "Get log format answer:"); + + if(iso14443_4a_error != Iso14443_4aErrorNone) { + FURI_LOG_E(TAG, "Failed to get log format, error %u", iso14443_4a_error); + error = emv_process_error(iso14443_4a_error); + break; + } + + const uint8_t* buff = bit_buffer_get_data(instance->rx_buffer); + + if(!emv_decode_response_tlv( + buff, + bit_buffer_get_size_bytes(instance->rx_buffer), + &instance->data->emv_application)) { + error = EmvErrorProtocol; + FURI_LOG_E(TAG, "Failed to parse log format"); + } + } while(false); + + return error; +} + +EmvError emv_poller_read_log_entry(EmvPoller* instance) { + EmvError error = EmvErrorProtocol; + + uint8_t records = instance->data->emv_application.log_records; + if(records == 0) { + return false; + } + + error = emv_poller_get_log_format(instance); + if(error != EmvErrorNone) return false; + + FURI_LOG_D(TAG, "Read Transaction logs"); + + uint8_t sfi = instance->data->emv_application.log_sfi; + uint8_t record_start = 1; + uint8_t record_end = records; + // Iterate through all records in file + for(uint8_t record = record_start; record <= record_end; ++record) { + error = emv_poller_read_sfi_record(instance, sfi, record); + if(error != EmvErrorNone) break; + if(!emv_decode_tl( + bit_buffer_get_data(instance->rx_buffer), + bit_buffer_get_size_bytes(instance->rx_buffer), + instance->data->emv_application.log_fmt, + instance->data->emv_application.log_fmt_len, + &instance->data->emv_application)) { + error = EmvErrorProtocol; + FURI_LOG_T(TAG, "Failed to parse log SFI 0x%X record %d", sfi, record); + break; + } + + instance->data->emv_application.active_tr++; + furi_check( + instance->data->emv_application.active_tr < + COUNT_OF(instance->data->emv_application.trans)); + } + + return error; +} diff --git a/lib/nfc/protocols/emv/emv_poller_i.h b/lib/nfc/protocols/emv/emv_poller_i.h index 4809a8668..554560a25 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.h +++ b/lib/nfc/protocols/emv/emv_poller_i.h @@ -14,6 +14,7 @@ typedef enum { EmvPollerStateSelectApplication, EmvPollerStateGetProcessingOptions, EmvPollerStateReadFiles, + EmvPollerStateReadLogs, EmvPollerStateReadFailed, EmvPollerStateReadSuccess, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 1976ef2de..f53c4d0ca 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,52.0,, +Version,+,52.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -888,7 +888,8 @@ Function,+,emv_get_uid,const uint8_t*,"const EmvData*, size_t*" Function,+,emv_is_equal,_Bool,"const EmvData*, const EmvData*" Function,+,emv_load,_Bool,"EmvData*, FlipperFormat*, uint32_t" Function,+,emv_poller_get_processing_options,EmvError,EmvPoller* -Function,+,emv_poller_read_files,EmvError,EmvPoller* +Function,+,emv_poller_read_afl,EmvError,EmvPoller* +Function,+,emv_poller_read_log_entry,EmvError,EmvPoller* Function,+,emv_poller_read_sfi_record,EmvError,"EmvPoller*, uint8_t, uint8_t" Function,+,emv_poller_select_application,EmvError,EmvPoller* Function,+,emv_poller_select_ppse,EmvError,EmvPoller* From 786f3568c0444f3aec98e04724fa326472f278f2 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Sun, 28 Jan 2024 20:18:17 +0000 Subject: [PATCH 098/110] Fix retry loop (on Android HCE) --- lib/nfc/helpers/iso14443_4_layer.c | 8 ++++---- lib/nfc/protocols/emv/emv_poller_i.c | 12 ++++++++++-- lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 2 +- lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c | 7 +++++-- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/nfc/helpers/iso14443_4_layer.c b/lib/nfc/helpers/iso14443_4_layer.c index 5b57d918c..7f0f0a25e 100644 --- a/lib/nfc/helpers/iso14443_4_layer.c +++ b/lib/nfc/helpers/iso14443_4_layer.c @@ -79,6 +79,7 @@ Iso14443_4aError iso14443_4_layer_decode_block_pwt_ext( furi_assert(instance); Iso14443_4aError ret = Iso14443_4aErrorProtocol; + bit_buffer_reset(output_data); do { const uint8_t pcb_field = bit_buffer_get_byte(block_data, 0); @@ -89,8 +90,8 @@ Iso14443_4aError iso14443_4_layer_decode_block_pwt_ext( bit_buffer_copy_right(output_data, block_data, 1); ret = Iso14443_4aErrorNone; } else { - // TODO: Need send request again - ret = Iso14443_4aErrorProtocol; + // send original request again + ret = Iso14443_4aErrorSendExtra; } break; case ISO14443_4_BLOCK_PCB_R: @@ -103,12 +104,11 @@ Iso14443_4aError iso14443_4_layer_decode_block_pwt_ext( const uint8_t wtxm = inf_field & 0b111111; //uint32_t fwt_temp = MIN((fwt * wtxm), fwt_max); - bit_buffer_reset(output_data); bit_buffer_append_byte( output_data, ISO14443_4_BLOCK_PCB_S | ISO14443_4_BLOCK_PCB_S_WTX | ISO14443_4_BLOCK_PCB); bit_buffer_append_byte(output_data, wtxm); - ret = Iso14443_4aErrorSendCtrl; + ret = Iso14443_4aErrorSendExtra; } break; } diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index eb27786cc..99e7c9759 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -208,6 +208,14 @@ static bool success = true; break; } + case EMV_TAG_CARDHOLDER_NAME: { + char name[27]; + memcpy(name, &buff[i], tlen); + name[tlen] = '\0'; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_CARDHOLDER_NAME %x: %s", tag, name); + break; + } case EMV_TAG_PAN: memcpy(app->pan, &buff[i], tlen); app->pan_len = tlen; @@ -654,11 +662,11 @@ EmvError emv_poller_read_log_entry(EmvPoller* instance) { uint8_t records = instance->data->emv_application.log_records; if(records == 0) { - return false; + return error; } error = emv_poller_get_log_format(instance); - if(error != EmvErrorNone) return false; + if(error != EmvErrorNone) return error; FURI_LOG_D(TAG, "Read Transaction logs"); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index add93cea1..05a7bd577 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -13,7 +13,7 @@ typedef enum { Iso14443_4aErrorNotPresent, Iso14443_4aErrorProtocol, Iso14443_4aErrorTimeout, - Iso14443_4aErrorSendCtrl, + Iso14443_4aErrorSendExtra, } Iso14443_4aError; typedef enum { diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index 529c74e27..b8e2ebda6 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -88,6 +88,7 @@ Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext( BitBuffer* rx_buffer) { furi_assert(instance); + uint8_t retry = 5; bit_buffer_reset(instance->tx_buffer); iso14443_4_layer_encode_block(instance->iso14443_4_layer, tx_buffer, instance->tx_buffer); @@ -108,9 +109,11 @@ Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext( } else { error = iso14443_4_layer_decode_block_pwt_ext( instance->iso14443_4_layer, rx_buffer, instance->rx_buffer); - if(error == Iso14443_4aErrorSendCtrl) { + if(error == Iso14443_4aErrorSendExtra) { + if(--retry == 0) break; // Send response for Control message - bit_buffer_copy(instance->tx_buffer, rx_buffer); + if(bit_buffer_get_size_bytes(rx_buffer)) + bit_buffer_copy(instance->tx_buffer, rx_buffer); continue; } break; From 1074af905c960b7a9a5ca1cd6e15413306f76d34 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Sun, 28 Jan 2024 22:45:26 +0000 Subject: [PATCH 099/110] Use render * Add transactions menu item * Use nfc assets for country/currency/aid * remove deprecated render --- applications/main/nfc/application.fam | 8 - .../main/nfc/helpers/nfc_emv_parser.c | 2 +- .../main/nfc/helpers/nfc_emv_parser.h | 2 +- .../nfc/helpers/protocol_support/emv/emv.c | 2 +- .../helpers/protocol_support/emv/emv_render.c | 119 ++- .../helpers/protocol_support/emv/emv_render.h | 4 +- applications/main/nfc/nfc_app_i.h | 1 + .../main/nfc/plugins/supported_cards/emv.c | 934 ------------------ .../main/nfc/scenes/nfc_scene_emv_more_info.c | 25 +- 9 files changed, 105 insertions(+), 992 deletions(-) delete mode 100644 applications/main/nfc/plugins/supported_cards/emv.c diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 0ed7a6241..86eefe620 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -182,14 +182,6 @@ App( sources=["plugins/supported_cards/ndef.c"], ) -App( - appid="emv_parser", - apptype=FlipperAppType.PLUGIN, - entry_point="emv_plugin_ep", - targets=["f7"], - requires=["nfc"], - sources=["plugins/supported_cards/emv.c"], -) App( appid="nfc_start", diff --git a/applications/main/nfc/helpers/nfc_emv_parser.c b/applications/main/nfc/helpers/nfc_emv_parser.c index 30e102405..f48a63d8f 100644 --- a/applications/main/nfc/helpers/nfc_emv_parser.c +++ b/applications/main/nfc/helpers/nfc_emv_parser.c @@ -34,7 +34,7 @@ static bool nfc_emv_parser_search_data( bool nfc_emv_parser_get_aid_name( Storage* storage, - uint8_t* aid, + const uint8_t* aid, uint8_t aid_len, FuriString* aid_name) { furi_assert(storage); diff --git a/applications/main/nfc/helpers/nfc_emv_parser.h b/applications/main/nfc/helpers/nfc_emv_parser.h index c636ca77d..03edab0a8 100644 --- a/applications/main/nfc/helpers/nfc_emv_parser.h +++ b/applications/main/nfc/helpers/nfc_emv_parser.h @@ -13,7 +13,7 @@ */ bool nfc_emv_parser_get_aid_name( Storage* storage, - uint8_t* aid, + const uint8_t* aid, uint8_t aid_len, FuriString* aid_name); diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv.c b/applications/main/nfc/helpers/protocol_support/emv/emv.c index 0b60bea6e..e543291cc 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv.c @@ -75,7 +75,7 @@ static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) { // } const NfcProtocolSupportBase nfc_protocol_support_emv = { - .features = NfcProtocolFeatureNone, + .features = NfcProtocolFeatureMoreInfo, .scene_info = { diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c index 10333a936..463f7355e 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -1,6 +1,7 @@ #include "emv_render.h" #include "../iso14443_4a/iso14443_4a_render.h" +#include "nfc/nfc_app_i.h" void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str) { nfc_render_emv_name(data->emv_application.name, str); @@ -17,10 +18,18 @@ void nfc_render_emv_data(const EmvData* data, FuriString* str) { void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str) { if(len == 0) return; - furi_string_cat_printf(str, "PAN: "); - for(uint8_t i = 0; i < len; i += 2) { - furi_string_cat_printf(str, "%02X%02X ", data[i], data[i + 1]); + + FuriString* card_number = furi_string_alloc(); + for(uint8_t i = 0; i < len; i++) { + if((i % 2 == 0) && (i != 0)) furi_string_cat_printf(card_number, " "); + furi_string_cat_printf(card_number, "%02X", data[i]); } + + // Cut padding 'F' from card number + furi_string_trim(card_number, "F"); + furi_string_cat(str, card_number); + furi_string_free(card_number); + furi_string_cat_printf(str, "\n"); } @@ -29,16 +38,27 @@ void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str) { furi_string_cat_printf(str, "Exp: %02X/%02X\n", apl->exp_month, apl->exp_year); } -void nfc_render_emv_currency(const EmvApplication* apl, FuriString* str) { - UNUSED(apl); - UNUSED(str); - // nfc/assets/currency_code.nfc +void nfc_render_emv_currency(uint16_t cur_code, FuriString* str) { + if(!cur_code) return; + + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* currency_name = furi_string_alloc(); + if(nfc_emv_parser_get_currency_name(storage, cur_code, currency_name)) { + furi_string_cat_printf(str, "Currency: %s\n", furi_string_get_cstr(currency_name)); + } + furi_string_free(currency_name); + furi_record_close(RECORD_STORAGE); } -void nfc_render_emv_country(const EmvApplication* apl, FuriString* str) { - UNUSED(apl); - UNUSED(str); - // nfc/assets/country_code.nfc +void nfc_render_emv_country(uint16_t country_code, FuriString* str) { + if(!country_code) return; + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* country_name = furi_string_alloc(); + if(nfc_emv_parser_get_country_name(storage, country_code, country_name)) { + furi_string_cat_printf(str, "Country: %s\n", furi_string_get_cstr(country_name)); + } + furi_string_free(country_name); + furi_record_close(RECORD_STORAGE); } void nfc_render_emv_name(const char* data, FuriString* str) { @@ -50,28 +70,48 @@ void nfc_render_emv_name(const char* data, FuriString* str) { void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { const uint8_t len = apl->aid_len; - if(len) { - furi_string_cat_printf(str, "AID: "); - for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]); - // nfc/assets/aid.nfc - } else { - furi_string_cat_printf(str, "No Pay Application found"); + + if(!len) { + furi_string_cat_printf(str, "No Pay Application found\n"); + return; } + + furi_string_cat_printf(str, "AID: "); + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* aid_name = furi_string_alloc(); + + if(nfc_emv_parser_get_aid_name(storage, apl->aid, len, aid_name)) { + furi_string_cat_printf(str, "%s", furi_string_get_cstr(aid_name)); + } else { + for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]); + } + furi_string_cat_printf(str, "\n"); + furi_string_free(aid_name); + furi_record_close(RECORD_STORAGE); } void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { const uint8_t len = apl->active_tr; if(!len) { + furi_string_cat_printf(str, "No transaction info\n"); return; } - furi_string_cat_printf(str, "Transactions:\n"); + + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* tmp = furi_string_alloc(); + + //furi_string_cat_printf(str, "Transactions:\n"); for(int i = 0; i < len; i++) { if(!apl->trans[i].amount) continue; + // transaction counter + furi_string_cat_printf(str, "\e#%d: ", apl->trans[i].atc); + + // Print transaction amount uint8_t* a = (uint8_t*)&apl->trans[i].amount; - furi_string_cat_printf(str, "%d: ", apl->trans[i].atc); bool top = true; for(int x = 0; x < 6; x++) { + // cents if(x == 5) { furi_string_cat_printf(str, ".%02X", a[x]); break; @@ -85,31 +125,46 @@ void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { } } } - // TODO to string - furi_string_cat_printf(str, " %x\n", apl->trans[i].currency); - // TODO to string - if(apl->trans[i].country) - furi_string_cat_printf(str, "country: %x\n", apl->trans[i].country); + if(apl->trans[i].currency) { + furi_string_set_str(tmp, "UNK"); + nfc_emv_parser_get_currency_name(storage, apl->trans[i].currency, tmp); + furi_string_cat_printf(str, " %s\n", furi_string_get_cstr(tmp)); + } + + if(apl->trans[i].country) { + furi_string_set_str(tmp, "UNK"); + nfc_emv_parser_get_country_name(storage, apl->trans[i].country, tmp); + furi_string_cat_printf(str, "Country: %s\n", furi_string_get_cstr(tmp)); + } + + if(apl->trans[i].date) + furi_string_cat_printf( + str, + "%02lx/%02lx/%02lx ", + apl->trans[i].date >> 16, + (apl->trans[i].date >> 8) & 0xff, + apl->trans[i].date & 0xff); if(apl->trans[i].time) furi_string_cat_printf( str, - "%02lx:%02lx:%02lx ", + "%02lx:%02lx:%02lx\n", apl->trans[i].time & 0xff, (apl->trans[i].time >> 8) & 0xff, apl->trans[i].time >> 16); - if(apl->trans[i].date) - furi_string_cat_printf( - str, - "%02lx/%02lx/%02lx\n", - apl->trans[i].date >> 16, - (apl->trans[i].date >> 8) & 0xff, - apl->trans[i].date & 0xff); } + + furi_string_free(tmp); + furi_record_close(RECORD_STORAGE); } void nfc_render_emv_extra(const EmvData* data, FuriString* str) { + nfc_render_emv_currency(data->emv_application.currency_code, str); + nfc_render_emv_country(data->emv_application.country_code, str); nfc_render_emv_application(&data->emv_application, str); + // PIN try + // transactions counter + //nfc_render_emv_transactions(&data->emv_application, str); } diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h index fd73cfc6b..80f80d423 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h @@ -19,8 +19,8 @@ void nfc_render_emv_extra(const EmvData* data, FuriString* str); void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str); -void nfc_render_emv_country(const EmvApplication* apl, FuriString* str); +void nfc_render_emv_country(uint16_t country_code, FuriString* str); -void nfc_render_emv_currency(const EmvApplication* apl, FuriString* str); +void nfc_render_emv_currency(uint16_t cur_code, FuriString* str); void nfc_render_emv_transactions(const EmvApplication* data, FuriString* str); \ No newline at end of file diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 943d722f8..0339bf92e 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -30,6 +30,7 @@ #include "helpers/mf_ultralight_auth.h" #include "helpers/mf_user_dict.h" #include "helpers/mfkey32_logger.h" +#include "helpers/nfc_emv_parser.h" #include "helpers/mf_classic_key_cache.h" #include "helpers/nfc_supported_cards.h" diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c deleted file mode 100644 index 09eb804e5..000000000 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ /dev/null @@ -1,934 +0,0 @@ -/* - * Parser for EMV cards. - * - * Copyright 2023 Leptoptilos - * - * 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 . - */ -#include "core/string.h" -#include "furi_hal_rtc.h" -#include "nfc_supported_card_plugin.h" - -#include "protocols/emv/emv.h" -#include "protocols/nfc_protocol.h" -#include - -#include -#include - -#define TAG "EMV" - -char* get_country_name(uint16_t country_code) { - switch(country_code) { - case 0x0004: - return "AFG"; - case 0x0008: - return "ALB"; - case 0x0010: - return "ATA"; - case 0x0012: - return "DZA"; - case 0x0016: - return "ASM"; - case 0x0020: - return "AND"; - case 0x0024: - return "AGO"; - case 0x0028: - return "ATG"; - case 0x0031: - return "AZE"; - case 0x0032: - return "ARG"; - case 0x0036: - return "AUS"; - case 0x0040: - return "AUT"; - case 0x0044: - return "BHS"; - case 0x0048: - return "BHR"; - case 0x0050: - return "BGD"; - case 0x0051: - return "ARM"; - case 0x0052: - return "BRB"; - case 0x0056: - return "BEL"; - case 0x0060: - return "BMU"; - case 0x0064: - return "BTN"; - case 0x0068: - return "BOL"; - case 0x0070: - return "BIH"; - case 0x0072: - return "BWA"; - case 0x0074: - return "BVT"; - case 0x0076: - return "BRA"; - case 0x0084: - return "BLZ"; - case 0x0086: - return "IOT"; - case 0x0090: - return "SLB"; - case 0x0092: - return "VGB"; - case 0x0096: - return "BRN"; - case 0x0100: - return "BGR"; - case 0x0104: - return "MMR"; - case 0x0108: - return "BDI"; - case 0x0112: - return "BLR"; - case 0x0116: - return "KHM"; - case 0x0120: - return "CMR"; - case 0x0124: - return "CAN"; - case 0x0132: - return "CPV"; - case 0x0136: - return "CYM"; - case 0x0140: - return "CAF"; - case 0x0144: - return "LKA"; - case 0x0148: - return "TCD"; - case 0x0152: - return "CHL"; - case 0x0156: - return "CHN"; - case 0x0158: - return "TWN"; - case 0x0162: - return "CXR"; - case 0x0166: - return "CCK"; - case 0x0170: - return "COL"; - case 0x0174: - return "COM"; - case 0x0175: - return "MYT"; - case 0x0178: - return "COG"; - case 0x0180: - return "COD"; - case 0x0184: - return "COK"; - case 0x0188: - return "CRI"; - case 0x0191: - return "HRV"; - case 0x0192: - return "CUB"; - case 0x0196: - return "CYP"; - case 0x0203: - return "CZE"; - case 0x0204: - return "BEN"; - case 0x0208: - return "DNK"; - case 0x0212: - return "DMA"; - case 0x0214: - return "DOM"; - case 0x0218: - return "ECU"; - case 0x0222: - return "SLV"; - case 0x0226: - return "GNQ"; - case 0x0231: - return "ETH"; - case 0x0232: - return "ERI"; - case 0x0233: - return "EST"; - case 0x0234: - return "FRO"; - case 0x0238: - return "FLK"; - case 0x0239: - return "SGS"; - case 0x0242: - return "FJI"; - case 0x0246: - return "FIN"; - case 0x0248: - return "ALA"; - case 0x0250: - return "FRA"; - case 0x0254: - return "GUF"; - case 0x0258: - return "PYF"; - case 0x0260: - return "ATF"; - case 0x0262: - return "DJI"; - case 0x0266: - return "GAB"; - case 0x0268: - return "GEO"; - case 0x0270: - return "GMB"; - case 0x0275: - return "PSE"; - case 0x0276: - return "DEU"; - case 0x0288: - return "GHA"; - case 0x0292: - return "GIB"; - case 0x0296: - return "KIR"; - case 0x0300: - return "GRC"; - case 0x0304: - return "GRL"; - case 0x0308: - return "GRD"; - case 0x0312: - return "GLP"; - case 0x0316: - return "GUM"; - case 0x0320: - return "GTM"; - case 0x0324: - return "GIN"; - case 0x0328: - return "GUY"; - case 0x0332: - return "HTI"; - case 0x0334: - return "HMD"; - case 0x0336: - return "VAT"; - case 0x0340: - return "HND"; - case 0x0344: - return "HKG"; - case 0x0348: - return "HUN"; - case 0x0352: - return "ISL"; - case 0x0356: - return "IND"; - case 0x0360: - return "IDN"; - case 0x0364: - return "IRN"; - case 0x0368: - return "IRQ"; - case 0x0372: - return "IRL"; - case 0x0376: - return "ISR"; - case 0x0380: - return "ITA"; - case 0x0384: - return "CIV"; - case 0x0388: - return "JAM"; - case 0x0392: - return "JPN"; - case 0x0398: - return "KAZ"; - case 0x0400: - return "JOR"; - case 0x0404: - return "KEN"; - case 0x0408: - return "PRK"; - case 0x0410: - return "KOR"; - case 0x0414: - return "KWT"; - case 0x0417: - return "KGZ"; - case 0x0418: - return "LAO"; - case 0x0422: - return "LBN"; - case 0x0426: - return "LSO"; - case 0x0428: - return "LVA"; - case 0x0430: - return "LBR"; - case 0x0434: - return "LBY"; - case 0x0438: - return "LIE"; - case 0x0440: - return "LTU"; - case 0x0442: - return "LUX"; - case 0x0446: - return "MAC"; - case 0x0450: - return "MDG"; - case 0x0454: - return "MWI"; - case 0x0458: - return "MYS"; - case 0x0462: - return "MDV"; - case 0x0466: - return "MLI"; - case 0x0470: - return "MLT"; - case 0x0474: - return "MTQ"; - case 0x0478: - return "MRT"; - case 0x0480: - return "MUS"; - case 0x0484: - return "MEX"; - case 0x0492: - return "MCO"; - case 0x0496: - return "MNG"; - case 0x0498: - return "MDA"; - case 0x0499: - return "MNE"; - case 0x0500: - return "MSR"; - case 0x0504: - return "MAR"; - case 0x0508: - return "MOZ"; - case 0x0512: - return "OMN"; - case 0x0516: - return "NAM"; - case 0x0520: - return "NRU"; - case 0x0524: - return "NPL"; - case 0x0528: - return "NLD"; - case 0x0531: - return "CUW"; - case 0x0533: - return "ABW"; - case 0x0534: - return "SXM"; - case 0x0535: - return "BES"; - case 0x0540: - return "NCL"; - case 0x0548: - return "VUT"; - case 0x0554: - return "NZL"; - case 0x0558: - return "NIC"; - case 0x0562: - return "NER"; - case 0x0566: - return "NGA"; - case 0x0570: - return "NIU"; - case 0x0574: - return "NFK"; - case 0x0578: - return "NOR"; - case 0x0580: - return "MNP"; - case 0x0581: - return "UMI"; - case 0x0583: - return "FSM"; - case 0x0584: - return "MHL"; - case 0x0585: - return "PLW"; - case 0x0586: - return "PAK"; - case 0x0591: - return "PAN"; - case 0x0598: - return "PNG"; - case 0x0600: - return "PRY"; - case 0x0604: - return "PER"; - case 0x0608: - return "PHL"; - case 0x0612: - return "PCN"; - case 0x0616: - return "POL"; - case 0x0620: - return "PRT"; - case 0x0624: - return "GNB"; - case 0x0626: - return "TLS"; - case 0x0630: - return "PRI"; - case 0x0634: - return "QAT"; - case 0x0638: - return "REU"; - case 0x0642: - return "ROU"; - case 0x0643: - return "RUS"; - case 0x0646: - return "RWA"; - case 0x0652: - return "BLM"; - case 0x0654: - return "SHN"; - case 0x0659: - return "KNA"; - case 0x0660: - return "AIA"; - case 0x0662: - return "LCA"; - case 0x0663: - return "MAF"; - case 0x0666: - return "SPM"; - case 0x0670: - return "VCT"; - case 0x0674: - return "SMR"; - case 0x0678: - return "STP"; - case 0x0682: - return "SAU"; - case 0x0686: - return "SEN"; - case 0x0688: - return "SRB"; - case 0x0690: - return "SYC"; - case 0x0694: - return "SLE"; - case 0x0702: - return "SGP"; - case 0x0703: - return "SVK"; - case 0x0704: - return "VNM"; - case 0x0705: - return "SVN"; - case 0x0706: - return "SOM"; - case 0x0710: - return "ZAF"; - case 0x0716: - return "ZWE"; - case 0x0724: - return "ESP"; - case 0x0728: - return "SSD"; - case 0x0729: - return "SDN"; - case 0x0732: - return "ESH"; - case 0x0740: - return "SUR"; - case 0x0744: - return "SJM"; - case 0x0748: - return "SWZ"; - case 0x0752: - return "SWE"; - case 0x0756: - return "CHE"; - case 0x0760: - return "SYR"; - case 0x0762: - return "TJK"; - case 0x0764: - return "THA"; - case 0x0768: - return "TGO"; - case 0x0772: - return "TKL"; - case 0x0776: - return "TON"; - case 0x0780: - return "TTO"; - case 0x0784: - return "ARE"; - case 0x0788: - return "TUN"; - case 0x0792: - return "TUR"; - case 0x0795: - return "TKM"; - case 0x0796: - return "TCA"; - case 0x0798: - return "TUV"; - case 0x0800: - return "UGA"; - case 0x0804: - return "UKR"; - case 0x0807: - return "MKD"; - case 0x0818: - return "EGY"; - case 0x0826: - return "GBR"; - case 0x0831: - return "GGY"; - case 0x0832: - return "JEY"; - case 0x0833: - return "IMN"; - case 0x0834: - return "TZA"; - case 0x0840: - return "USA"; - case 0x0850: - return "VIR"; - case 0x0854: - return "BFA"; - case 0x0858: - return "URY"; - case 0x0860: - return "UZB"; - case 0x0862: - return "VEN"; - case 0x0876: - return "WLF"; - case 0x0882: - return "WSM"; - case 0x0887: - return "YEM"; - case 0x0894: - return "ZMB"; - default: - return "UNKNOWN"; - } -} - -char* get_currency_name(uint16_t currency_code) { - switch(currency_code) { - case 0x0997: - return "USN"; - case 0x0994: - return "XSU"; - case 0x0990: - return "CLF"; - case 0x0986: - return "BRL"; - case 0x0985: - return "PLN"; - case 0x0984: - return "BOV"; - case 0x0981: - return "GEL"; - case 0x0980: - return "UAH"; - case 0x0979: - return "MXV"; - case 0x0978: - return "EUR"; - case 0x0977: - return "BAM"; - case 0x0976: - return "CDF"; - case 0x0975: - return "BGN"; - case 0x0973: - return "AOA"; - case 0x0972: - return "TJS"; - case 0x0971: - return "AFN"; - case 0x0970: - return "COU"; - case 0x0969: - return "MGA"; - case 0x0968: - return "SRD"; - case 0x0967: - return "ZMW"; - case 0x0965: - return "XUA"; - case 0x0960: - return "XDR"; - case 0x0953: - return "XPF"; - case 0x0952: - return "XOF"; - case 0x0951: - return "XCD"; - case 0x0950: - return "XAF"; - case 0x0949: - return "TRY"; - case 0x0948: - return "CHW"; - case 0x0947: - return "CHE"; - case 0x0946: - return "RON"; - case 0x0944: - return "AZN"; - case 0x0943: - return "MZN"; - case 0x0941: - return "RSD"; - case 0x0940: - return "UYI"; - case 0x0938: - return "SDG"; - case 0x0937: - return "VEF"; - case 0x0936: - return "GHS"; - case 0x0934: - return "TMT"; - case 0x0933: - return "BYN"; - case 0x0932: - return "ZWL"; - case 0x0931: - return "CUC"; - case 0x0930: - return "STN"; - case 0x0929: - return "MRU"; - case 0x0901: - return "TWD"; - case 0x0886: - return "YER"; - case 0x0882: - return "WST"; - case 0x0860: - return "UZS"; - case 0x0858: - return "UYU"; - case 0x0840: - return "USD"; - case 0x0834: - return "TZS"; - case 0x0826: - return "GBP"; - case 0x0818: - return "EGP"; - case 0x0807: - return "MKD"; - case 0x0800: - return "UGX"; - case 0x0788: - return "TND"; - case 0x0784: - return "AED"; - case 0x0780: - return "TTD"; - case 0x0776: - return "TOP"; - case 0x0764: - return "THB"; - case 0x0760: - return "SYP"; - case 0x0756: - return "CHF"; - case 0x0752: - return "SEK"; - case 0x0748: - return "SZL"; - case 0x0728: - return "SSP"; - case 0x0710: - return "ZAR"; - case 0x0706: - return "SOS"; - case 0x0704: - return "VND"; - case 0x0702: - return "SGD"; - case 0x0694: - return "SLL"; - case 0x0690: - return "SCR"; - case 0x0682: - return "SAR"; - case 0x0654: - return "SHP"; - case 0x0646: - return "RWF"; - case 0x0643: - return "RUB"; - case 0x0634: - return "QAR"; - case 0x0608: - return "PHP"; - case 0x0604: - return "PEN"; - case 0x0600: - return "PYG"; - case 0x0598: - return "PGK"; - case 0x0590: - return "PAB"; - case 0x0586: - return "PKR"; - case 0x0578: - return "NOK"; - case 0x0566: - return "NGN"; - case 0x0558: - return "NIO"; - case 0x0554: - return "NZD"; - case 0x0548: - return "VUV"; - case 0x0533: - return "AWG"; - case 0x0532: - return "ANG"; - case 0x0524: - return "NPR"; - case 0x0516: - return "NAD"; - case 0x0512: - return "OMR"; - case 0x0504: - return "MAD"; - case 0x0498: - return "MDL"; - case 0x0496: - return "MNT"; - case 0x0484: - return "MXN"; - case 0x0480: - return "MUR"; - case 0x0462: - return "MVR"; - case 0x0458: - return "MYR"; - case 0x0454: - return "MWK"; - case 0x0446: - return "MOP"; - case 0x0434: - return "LYD"; - case 0x0430: - return "LRD"; - case 0x0426: - return "LSL"; - case 0x0422: - return "LBP"; - case 0x0418: - return "LAK"; - case 0x0417: - return "KGS"; - case 0x0414: - return "KWD"; - case 0x0410: - return "KRW"; - case 0x0408: - return "KPW"; - case 0x0404: - return "KES"; - case 0x0400: - return "JOD"; - case 0x0398: - return "KZT"; - case 0x0392: - return "JPY"; - case 0x0388: - return "JMD"; - case 0x0376: - return "ILS"; - case 0x0368: - return "IQD"; - case 0x0364: - return "IRR"; - case 0x0360: - return "IDR"; - case 0x0356: - return "INR"; - case 0x0352: - return "ISK"; - case 0x0348: - return "HUF"; - case 0x0344: - return "HKD"; - case 0x0340: - return "HNL"; - case 0x0332: - return "HTG"; - case 0x0328: - return "GYD"; - case 0x0324: - return "GNF"; - case 0x0320: - return "GTQ"; - case 0x0292: - return "GIP"; - case 0x0270: - return "GMD"; - case 0x0262: - return "DJF"; - case 0x0242: - return "FJD"; - case 0x0238: - return "FKP"; - case 0x0232: - return "ERN"; - case 0x0230: - return "ETB"; - case 0x0222: - return "SVC"; - case 0x0214: - return "DOP"; - case 0x0208: - return "DKK"; - case 0x0203: - return "CZK"; - case 0x0192: - return "CUP"; - case 0x0191: - return "HRK"; - case 0x0188: - return "CRC"; - case 0x0174: - return "KMF"; - case 0x0170: - return "COP"; - case 0x0156: - return "CNY"; - case 0x0152: - return "CLP"; - case 0x0144: - return "LKR"; - case 0x0136: - return "KYD"; - case 0x0132: - return "CVE"; - case 0x0124: - return "CAD"; - case 0x0116: - return "KHR"; - case 0x0108: - return "BIF"; - case 0x0104: - return "MMK"; - case 0x0096: - return "BND"; - case 0x0090: - return "SBD"; - case 0x0084: - return "BZD"; - case 0x0072: - return "BWP"; - case 0x0068: - return "BOB"; - case 0x0064: - return "BTN"; - case 0x0060: - return "BMD"; - case 0x0052: - return "BBD"; - case 0x0051: - return "AMD"; - case 0x0050: - return "BDT"; - case 0x0048: - return "BHD"; - case 0x0044: - return "BSD"; - case 0x0036: - return "AUD"; - case 0x0032: - return "ARS"; - case 0x0012: - return "DZD"; - case 0x0008: - return "ALL"; - default: - return "UNKNOWN"; - } -} - -static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { - furi_assert(device); - bool parsed = false; - - const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); - const EmvApplication app = data->emv_application; - - do { - if(app.name_found) - furi_string_cat_printf(parsed_data, "\e#%s\n", app.name); - else - furi_string_cat_printf(parsed_data, "\e#%s\n", "EMV"); - - FuriString* card_number = furi_string_alloc(); - for(uint8_t i = 0; i < app.pan_len; i += 2) { - furi_string_cat_printf(card_number, "%02X%02X ", app.pan[i], app.pan[i + 1]); - } - - // Cut padding 'F' from card number - size_t end = furi_string_search_rchar(card_number, 'F'); - if(end) furi_string_left(card_number, end); - furi_string_cat(parsed_data, card_number); - furi_string_free(card_number); - - furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X", app.exp_month, app.exp_year); - - furi_string_cat_printf(parsed_data, "\nCountry: %s", get_country_name(app.country_code)); - furi_string_cat_printf( - parsed_data, " Currency: %s", get_currency_name(app.currency_code)); - - parsed = true; - } while(false); - - return parsed; -} - -/* Actual implementation of app<>plugin interface */ -static const NfcSupportedCardsPlugin emv_plugin = { - .protocol = NfcProtocolEmv, - .verify = NULL, - .read = NULL, - .parse = emv_parse, -}; - -/* Plugin descriptor to comply with basic plugin specification */ -static const FlipperAppPluginDescriptor emv_plugin_descriptor = { - .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, - .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, - .entry_point = &emv_plugin, -}; - -/* Plugin entry point - must return a pointer to const descriptor */ -const FlipperAppPluginDescriptor* emv_plugin_ep() { - return &emv_plugin_descriptor; -} \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_emv_more_info.c b/applications/main/nfc/scenes/nfc_scene_emv_more_info.c index 5825190d1..0cddce20a 100644 --- a/applications/main/nfc/scenes/nfc_scene_emv_more_info.c +++ b/applications/main/nfc/scenes/nfc_scene_emv_more_info.c @@ -9,7 +9,7 @@ enum { }; enum SubmenuIndex { - SubmenuIndexCardInfo, + SubmenuIndexTransactions, SubmenuIndexDynamic, // dynamic indices start here }; @@ -21,8 +21,8 @@ void nfc_scene_emv_more_info_on_enter(void* context) { submenu_add_item( submenu, - "Card info", - SubmenuIndexCardInfo, + "Transactions", + SubmenuIndexTransactions, nfc_protocol_support_common_submenu_callback, nfc); @@ -37,17 +37,17 @@ bool nfc_scene_emv_more_info_on_event(void* context, SceneManagerEvent event) { const EmvData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolEmv); if(event.type == SceneManagerEventTypeCustom) { - TextBox* text_box = nfc->text_box; - furi_string_reset(nfc->text_box_store); - - if(event.event == SubmenuIndexCardInfo) { - nfc_render_emv_data(data, nfc->text_box_store); - text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + if(event.event == SubmenuIndexTransactions) { + FuriString* temp_str = furi_string_alloc(); + nfc_render_emv_transactions(&data->emv_application, temp_str); + widget_add_text_scroll_element( + nfc->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneEmvMoreInfo, - EmvMoreInfoStateItem + SubmenuIndexCardInfo); + EmvMoreInfoStateItem + SubmenuIndexTransactions); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { @@ -69,7 +69,6 @@ void nfc_scene_emv_more_info_on_exit(void* context) { NfcApp* nfc = context; // Clear views - text_box_reset(nfc->text_box); - furi_string_reset(nfc->text_box_store); + widget_reset(nfc->widget); submenu_reset(nfc->submenu); } From 653af9a5cd49ac9fa05f0c4e679a915605ae2295 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Mon, 29 Jan 2024 00:07:17 +0000 Subject: [PATCH 100/110] Read PIN tries and transactions counters --- .../helpers/protocol_support/emv/emv_render.c | 17 +++++-- lib/nfc/protocols/emv/emv.c | 1 + lib/nfc/protocols/emv/emv.h | 8 ++++ lib/nfc/protocols/emv/emv_poller.c | 28 ++++------- lib/nfc/protocols/emv/emv_poller.h | 4 ++ lib/nfc/protocols/emv/emv_poller_i.c | 48 ++++++++++++++----- lib/nfc/protocols/emv/emv_poller_i.h | 2 +- targets/f7/api_symbols.csv | 4 +- 8 files changed, 74 insertions(+), 38 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c index 463f7355e..cc8a46efe 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -91,10 +91,20 @@ void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { furi_record_close(RECORD_STORAGE); } +static void nfc_render_emv_pin_try_counter(uint8_t counter, FuriString* str) { + if(counter == 0xff) return; + furi_string_cat_printf(str, "PIN try left: %d\n", counter); +} + void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { + if(apl->transaction_counter) + furi_string_cat_printf(str, "Transactions: %d\n", apl->transaction_counter); + if(apl->last_online_atc) + furi_string_cat_printf(str, "Last Online ATC: %d\n", apl->last_online_atc); + const uint8_t len = apl->active_tr; if(!len) { - furi_string_cat_printf(str, "No transaction info\n"); + furi_string_cat_printf(str, "No transactions info\n"); return; } @@ -163,8 +173,5 @@ void nfc_render_emv_extra(const EmvData* data, FuriString* str) { nfc_render_emv_currency(data->emv_application.currency_code, str); nfc_render_emv_country(data->emv_application.country_code, str); nfc_render_emv_application(&data->emv_application, str); - // PIN try - // transactions counter - - //nfc_render_emv_transactions(&data->emv_application, str); + nfc_render_emv_pin_try_counter(data->emv_application.pin_try_counter, str); } diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index 2a6c83101..bbeacffb8 100644 --- a/lib/nfc/protocols/emv/emv.c +++ b/lib/nfc/protocols/emv/emv.c @@ -27,6 +27,7 @@ const NfcDeviceBase nfc_device_emv = { EmvData* emv_alloc() { EmvData* data = malloc(sizeof(EmvData)); data->iso14443_4a_data = iso14443_4a_alloc(); + data->emv_application.pin_try_counter = 0xff; return data; } diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index b565ee334..42aa1a703 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -8,15 +8,19 @@ extern "C" { #define MAX_APDU_LEN 255 +#define EMV_REQ_GET_DATA 0x80CA + #define EMV_TAG_APP_TEMPLATE 0x61 #define EMV_TAG_AID 0x4F #define EMV_TAG_PRIORITY 0x87 #define EMV_TAG_PDOL 0x9F38 #define EMV_TAG_CARD_NAME 0x50 #define EMV_TAG_FCI 0xBF0C +#define EMV_TAG_PIN_TRY_COUNTER 0x9F17 #define EMV_TAG_LOG_ENTRY 0x9F4D #define EMV_TAG_LOG_FMT 0x9F4F +#define EMV_TAG_LAST_ONLINE_ATC 0x9F13 #define EMV_TAG_ATC 0x9F36 #define EMV_TAG_LOG_AMOUNT 0x9F02 #define EMV_TAG_LOG_COUNTRY 0x9F1A @@ -63,6 +67,7 @@ typedef struct { uint8_t log_fmt[50]; uint8_t log_fmt_len; uint8_t active_tr; + bool saving_trans_list; Transaction trans[16]; uint8_t priority; uint8_t aid[16]; @@ -75,6 +80,9 @@ typedef struct { uint8_t exp_year; uint16_t country_code; uint16_t currency_code; + uint8_t pin_try_counter; + uint16_t transaction_counter; + uint16_t last_online_atc; APDU pdol; APDU afl; } EmvApplication; diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c index 70051afcd..7907908fd 100644 --- a/lib/nfc/protocols/emv/emv_poller.c +++ b/lib/nfc/protocols/emv/emv_poller.c @@ -96,17 +96,12 @@ static NfcCommand emv_poller_handler_get_processing_options(EmvPoller* instance) if(instance->error == EmvErrorNone) { FURI_LOG_D(TAG, "Get processing options success"); - if(instance->data->emv_application.pan_len > 0) { - instance->state = EmvPollerStateReadSuccess; - } else { - FURI_LOG_D(TAG, "No PAN still. Read SFI files"); - instance->state = EmvPollerStateReadFiles; - } } else { FURI_LOG_E(TAG, "Failed to get processing options"); - instance->state = EmvPollerStateReadFiles; } + // Read another informations + instance->state = EmvPollerStateReadFiles; return NfcCommandContinue; } @@ -115,10 +110,7 @@ static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) { if(instance->error == EmvErrorNone) { FURI_LOG_D(TAG, "Read files success"); - if(instance->data->emv_application.log_sfi) - instance->state = EmvPollerStateReadLogs; - else - instance->state = EmvPollerStateReadSuccess; + instance->state = EmvPollerStateReadExtra; } else { FURI_LOG_E(TAG, "Failed to read files"); instance->state = EmvPollerStateReadFailed; @@ -127,14 +119,10 @@ static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) { return NfcCommandContinue; } -static NfcCommand emv_poller_handler_read_logs(EmvPoller* instance) { - instance->error = emv_poller_read_log_entry(instance); - - if(instance->error == EmvErrorNone) { - FURI_LOG_D(TAG, "Log entries had been read"); - } else { - FURI_LOG_D(TAG, "No log entry"); - } +static NfcCommand emv_poller_handler_read_extra_data(EmvPoller* instance) { + emv_poller_read_log_entry(instance); + emv_poller_get_last_online_atc(instance); + emv_poller_get_pin_try_counter(instance); instance->state = EmvPollerStateReadSuccess; return NfcCommandContinue; @@ -163,7 +151,7 @@ static const EmvPollerReadHandler emv_poller_read_handler[EmvPollerStateNum] = { [EmvPollerStateSelectApplication] = emv_poller_handler_select_application, [EmvPollerStateGetProcessingOptions] = emv_poller_handler_get_processing_options, [EmvPollerStateReadFiles] = emv_poller_handler_read_files, - [EmvPollerStateReadLogs] = emv_poller_handler_read_logs, + [EmvPollerStateReadExtra] = emv_poller_handler_read_extra_data, [EmvPollerStateReadFailed] = emv_poller_handler_read_fail, [EmvPollerStateReadSuccess] = emv_poller_handler_read_success, }; diff --git a/lib/nfc/protocols/emv/emv_poller.h b/lib/nfc/protocols/emv/emv_poller.h index c2335bfa4..64bd0be9d 100644 --- a/lib/nfc/protocols/emv/emv_poller.h +++ b/lib/nfc/protocols/emv/emv_poller.h @@ -50,6 +50,10 @@ EmvError emv_poller_read_afl(EmvPoller* instance); EmvError emv_poller_read_log_entry(EmvPoller* instance); +EmvError emv_poller_get_pin_try_counter(EmvPoller* instance); + +EmvError emv_poller_get_last_online_atc(EmvPoller* instance); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 99e7c9759..7288c473c 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -249,8 +249,15 @@ static bool app->log_sfi, app->log_records); break; + case EMV_TAG_LAST_ONLINE_ATC: + app->last_online_atc = (buff[i] << 8 | buff[i + 1]); + success = true; + break; case EMV_TAG_ATC: - app->trans[app->active_tr].atc = (buff[i] << 8 | buff[i + 1]); + if(app->saving_trans_list) + app->trans[app->active_tr].atc = (buff[i] << 8 | buff[i + 1]); + else + app->transaction_counter = (buff[i] << 8 | buff[i + 1]); success = true; break; case EMV_TAG_LOG_AMOUNT: @@ -273,6 +280,11 @@ static bool memcpy(&app->trans[app->active_tr].time, &buff[i], tlen); success = true; break; + case EMV_TAG_PIN_TRY_COUNTER: + app->pin_try_counter = buff[i]; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_PIN_TRY_COUNTER %x: %d", tag, app->pin_try_counter); + break; } return success; } @@ -616,29 +628,28 @@ EmvError emv_poller_read_afl(EmvPoller* instance) { return error; } -static EmvError emv_poller_get_log_format(EmvPoller* instance) { +static EmvError emv_poller_req_get_data(EmvPoller* instance, uint16_t tag) { EmvError error = EmvErrorNone; - const uint8_t cla_ins[] = {0x80, 0xCA}; - bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); - bit_buffer_copy_bytes(instance->tx_buffer, cla_ins, sizeof(cla_ins)); - bit_buffer_append_byte(instance->tx_buffer, EMV_TAG_LOG_FMT >> 8); - bit_buffer_append_byte(instance->tx_buffer, EMV_TAG_LOG_FMT & 0xFF); + bit_buffer_append_byte(instance->tx_buffer, EMV_REQ_GET_DATA >> 8); + bit_buffer_append_byte(instance->tx_buffer, EMV_REQ_GET_DATA & 0xFF); + bit_buffer_append_byte(instance->tx_buffer, tag >> 8); + bit_buffer_append_byte(instance->tx_buffer, tag & 0xFF); bit_buffer_append_byte(instance->tx_buffer, 0x00); //Length do { - FURI_LOG_D(TAG, "Get log format"); + FURI_LOG_D(TAG, "Get data for tag 0x%x", tag); Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block_pwt_ext( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); - emv_trace(instance, "Get log format answer:"); + emv_trace(instance, "Get log data answer:"); if(iso14443_4a_error != Iso14443_4aErrorNone) { - FURI_LOG_E(TAG, "Failed to get log format, error %u", iso14443_4a_error); + FURI_LOG_E(TAG, "Failed to get data, error %u", iso14443_4a_error); error = emv_process_error(iso14443_4a_error); break; } @@ -650,21 +661,35 @@ static EmvError emv_poller_get_log_format(EmvPoller* instance) { bit_buffer_get_size_bytes(instance->rx_buffer), &instance->data->emv_application)) { error = EmvErrorProtocol; - FURI_LOG_E(TAG, "Failed to parse log format"); + FURI_LOG_E(TAG, "Failed to parse get data"); } } while(false); return error; } +EmvError emv_poller_get_pin_try_counter(EmvPoller* instance) { + return emv_poller_req_get_data(instance, EMV_TAG_PIN_TRY_COUNTER); +} + +EmvError emv_poller_get_last_online_atc(EmvPoller* instance) { + return emv_poller_req_get_data(instance, EMV_TAG_LAST_ONLINE_ATC); +} + +static EmvError emv_poller_get_log_format(EmvPoller* instance) { + return emv_poller_req_get_data(instance, EMV_TAG_LOG_FMT); +} + EmvError emv_poller_read_log_entry(EmvPoller* instance) { EmvError error = EmvErrorProtocol; + if(!instance->data->emv_application.log_sfi) return error; uint8_t records = instance->data->emv_application.log_records; if(records == 0) { return error; } + instance->data->emv_application.saving_trans_list = true; error = emv_poller_get_log_format(instance); if(error != EmvErrorNone) return error; @@ -694,5 +719,6 @@ EmvError emv_poller_read_log_entry(EmvPoller* instance) { COUNT_OF(instance->data->emv_application.trans)); } + instance->data->emv_application.saving_trans_list = false; return error; } diff --git a/lib/nfc/protocols/emv/emv_poller_i.h b/lib/nfc/protocols/emv/emv_poller_i.h index 554560a25..620d2f359 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.h +++ b/lib/nfc/protocols/emv/emv_poller_i.h @@ -14,7 +14,7 @@ typedef enum { EmvPollerStateSelectApplication, EmvPollerStateGetProcessingOptions, EmvPollerStateReadFiles, - EmvPollerStateReadLogs, + EmvPollerStateReadExtra, EmvPollerStateReadFailed, EmvPollerStateReadSuccess, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index f53c4d0ca..948f957b5 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,52.1,, +Version,+,52.3,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -887,6 +887,8 @@ Function,+,emv_get_device_name,const char*,"const EmvData*, NfcDeviceNameType" Function,+,emv_get_uid,const uint8_t*,"const EmvData*, size_t*" Function,+,emv_is_equal,_Bool,"const EmvData*, const EmvData*" Function,+,emv_load,_Bool,"EmvData*, FlipperFormat*, uint32_t" +Function,+,emv_poller_get_last_online_atc,EmvError,EmvPoller* +Function,+,emv_poller_get_pin_try_counter,EmvError,EmvPoller* Function,+,emv_poller_get_processing_options,EmvError,EmvPoller* Function,+,emv_poller_read_afl,EmvError,EmvPoller* Function,+,emv_poller_read_log_entry,EmvError,EmvPoller* From 1165e25f0030f151e029936dbc2c5b2755930366 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Mon, 29 Jan 2024 13:48:33 +0000 Subject: [PATCH 101/110] Read all files --- lib/nfc/protocols/emv/emv_poller_i.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 7288c473c..2fbae4fc4 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -619,10 +619,7 @@ EmvError emv_poller_read_afl(EmvPoller* instance) { error = EmvErrorProtocol; FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record); } - if(instance->data->emv_application.pan_len != 0) - return EmvErrorNone; // Card number fetched } - error = EmvErrorProtocol; } return error; From 3612814a18e4ceaa85d3f2ac5b10e95b7d46433c Mon Sep 17 00:00:00 2001 From: Methodius Date: Mon, 29 Jan 2024 23:12:17 +0900 Subject: [PATCH 102/110] back to parser --- applications/main/nfc/application.fam | 10 +- .../nfc/helpers/protocol_support/emv/emv.c | 2 +- .../helpers/protocol_support/emv/emv_render.c | 9 +- .../main/nfc/plugins/supported_cards/emv.c | 131 ++++++++++++++++++ lib/nfc/helpers/iso14443_4_layer.c | 13 +- lib/nfc/protocols/nfc_listener_defs.c | 1 + 6 files changed, 155 insertions(+), 11 deletions(-) create mode 100644 applications/main/nfc/plugins/supported_cards/emv.c diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 86eefe620..569c680eb 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -173,6 +173,15 @@ App( sources=["plugins/supported_cards/washcity.c"], ) +App( + appid="emv_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="emv_plugin_ep", + targets=["f7"], + requires=["nfc"], + sources=["plugins/supported_cards/emv.c"], +) + App( appid="ndef_parser", apptype=FlipperAppType.PLUGIN, @@ -182,7 +191,6 @@ App( sources=["plugins/supported_cards/ndef.c"], ) - App( appid="nfc_start", targets=["f7"], diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv.c b/applications/main/nfc/helpers/protocol_support/emv/emv.c index e543291cc..0b60bea6e 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv.c @@ -75,7 +75,7 @@ static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) { // } const NfcProtocolSupportBase nfc_protocol_support_emv = { - .features = NfcProtocolFeatureMoreInfo, + .features = NfcProtocolFeatureNone, .scene_info = { diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c index cc8a46efe..2d76a3fb9 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -4,11 +4,12 @@ #include "nfc/nfc_app_i.h" void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str) { - nfc_render_emv_name(data->emv_application.name, str); - nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str); - nfc_render_emv_expired(&data->emv_application, str); + nfc_render_iso14443_4a_info(data->iso14443_4a_data, format_type, str); + // nfc_render_emv_name(data->emv_application.name, str); + // nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str); + // nfc_render_emv_expired(&data->emv_application, str); - if(format_type == NfcProtocolFormatTypeFull) nfc_render_emv_extra(data, str); + // if(format_type == NfcProtocolFormatTypeFull) nfc_render_emv_extra(data, str); } void nfc_render_emv_data(const EmvData* data, FuriString* str) { diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c new file mode 100644 index 000000000..99842f2d6 --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -0,0 +1,131 @@ +/* + * Parser for EMV cards. + * + * Copyright 2023 Leptoptilos + * + * 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 . + */ +#include "core/string.h" +#include "furi_hal_rtc.h" +#include "helpers/nfc_emv_parser.h" +#include "nfc_supported_card_plugin.h" + +#include "protocols/emv/emv.h" +#include "protocols/nfc_protocol.h" +#include + +#include +#include + +#define TAG "EMV" + +bool emv_get_currency_name(uint16_t cur_code, FuriString* currency_name) { + if(!cur_code) return false; + + Storage* storage = furi_record_open(RECORD_STORAGE); + + bool succsess = nfc_emv_parser_get_currency_name(storage, cur_code, currency_name); + + furi_record_close(RECORD_STORAGE); + return succsess; +} + +bool emv_get_country_name(uint16_t country_code, FuriString* country_name) { + if(!country_code) return false; + + Storage* storage = furi_record_open(RECORD_STORAGE); + + bool succsess = nfc_emv_parser_get_country_name(storage, country_code, country_name); + + furi_record_close(RECORD_STORAGE); + return succsess; +} + +bool emv_get_aid_name(const EmvApplication* apl, FuriString* aid_name) { + const uint8_t len = apl->aid_len; + + if(!len) return false; + + Storage* storage = furi_record_open(RECORD_STORAGE); + + bool succsess = nfc_emv_parser_get_aid_name(storage, apl->aid, len, aid_name); + + furi_record_close(RECORD_STORAGE); + return succsess; +} + +static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + bool parsed = false; + + const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); + const EmvApplication app = data->emv_application; + + do { + if(app.name_found) + furi_string_cat_printf(parsed_data, "\e#%s\n", app.name); + else + furi_string_cat_printf(parsed_data, "\e#%s\n", "EMV"); + + FuriString* pan = furi_string_alloc(); + for(uint8_t i = 0; i < app.pan_len; i += 2) { + furi_string_cat_printf(pan, "%02X%02X ", app.pan[i], app.pan[i + 1]); + } + + // Cut padding 'F' from card number + size_t end = furi_string_search_rchar(pan, 'F'); + if(end) furi_string_left(pan, end); + furi_string_cat(parsed_data, pan); + furi_string_free(pan); + + furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X", app.exp_month, app.exp_year); + + FuriString* str = furi_string_alloc(); + bool storage_readed = emv_get_country_name(app.country_code, str); + + if(storage_readed) + furi_string_cat_printf(parsed_data, "\nCountry: %s", furi_string_get_cstr(str)); + + storage_readed = emv_get_currency_name(app.currency_code, str); + if(storage_readed) + furi_string_cat_printf(parsed_data, "\nCurrency: %s", furi_string_get_cstr(str)); + + if(app.pin_try_counter != 0xFF) + furi_string_cat_printf(str, "\nPIN try left: %d\n", app.pin_try_counter); + + parsed = true; + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin emv_plugin = { + .protocol = NfcProtocolEmv, + .verify = NULL, + .read = NULL, + .parse = emv_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor emv_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &emv_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* emv_plugin_ep() { + return &emv_plugin_descriptor; +} \ No newline at end of file diff --git a/lib/nfc/helpers/iso14443_4_layer.c b/lib/nfc/helpers/iso14443_4_layer.c index 7f0f0a25e..b21e22423 100644 --- a/lib/nfc/helpers/iso14443_4_layer.c +++ b/lib/nfc/helpers/iso14443_4_layer.c @@ -3,15 +3,18 @@ #include #define ISO14443_4_BLOCK_PCB (1U << 1) -#define ISO14443_4_BLOCK_PCB_I (0U << 6) -#define ISO14443_4_BLOCK_PCB_R (2U << 6) +#define ISO14443_4_BLOCK_PCB_I (0U) +#define ISO14443_4_BLOCK_PCB_R (5U << 5) #define ISO14443_4_BLOCK_PCB_S (3U << 6) + +#define ISO14443_4_BLOCK_PCB_I_ (0U << 6) +#define ISO14443_4_BLOCK_PCB_R_ (2U << 6) #define ISO14443_4_BLOCK_PCB_TYPE_MASK (3U << 6) #define ISO14443_4_BLOCK_PCB_S_DESELECT (0U << 4) #define ISO14443_4_BLOCK_PCB_S_WTX (3U << 4) #define ISO14443_4_BLOCK_PCB_BLOCK_NUMBER (1U << 0) -#define ISO14443_4_BLOCK_PCB (1U << 1) + #define ISO14443_4_BLOCK_PCB_NAD (1U << 2) #define ISO14443_4_BLOCK_PCB_CID (1U << 3) #define ISO14443_4_BLOCK_PCB_CHAINING (1U << 4) @@ -85,7 +88,7 @@ Iso14443_4aError iso14443_4_layer_decode_block_pwt_ext( const uint8_t pcb_field = bit_buffer_get_byte(block_data, 0); const uint8_t block_type = pcb_field & ISO14443_4_BLOCK_PCB_TYPE_MASK; switch(block_type) { - case ISO14443_4_BLOCK_PCB_I: + case ISO14443_4_BLOCK_PCB_I_: if(pcb_field == instance->pcb_prev) { bit_buffer_copy_right(output_data, block_data, 1); ret = Iso14443_4aErrorNone; @@ -94,7 +97,7 @@ Iso14443_4aError iso14443_4_layer_decode_block_pwt_ext( ret = Iso14443_4aErrorSendExtra; } break; - case ISO14443_4_BLOCK_PCB_R: + case ISO14443_4_BLOCK_PCB_R_: // TODO break; case ISO14443_4_BLOCK_PCB_S: diff --git a/lib/nfc/protocols/nfc_listener_defs.c b/lib/nfc/protocols/nfc_listener_defs.c index 2a6167e9c..ecfe98c10 100644 --- a/lib/nfc/protocols/nfc_listener_defs.c +++ b/lib/nfc/protocols/nfc_listener_defs.c @@ -20,4 +20,5 @@ const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { [NfcProtocolSlix] = &nfc_listener_slix, [NfcProtocolSt25tb] = NULL, [NfcProtocolFelica] = &nfc_listener_felica, + [NfcProtocolEmv] = NULL, }; From a15312e0528bce3a01afa068b09173962ce7fb3c Mon Sep 17 00:00:00 2001 From: Methodius Date: Tue, 30 Jan 2024 00:29:06 +0900 Subject: [PATCH 103/110] parser fix --- applications/main/nfc/application.fam | 4 +- .../helpers/protocol_support/emv/emv_render.c | 74 ++++++++++--------- .../helpers/protocol_support/emv/emv_render.h | 6 +- .../main/nfc/plugins/supported_cards/emv.c | 8 +- 4 files changed, 50 insertions(+), 42 deletions(-) diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 569c680eb..ab9690ec1 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -178,8 +178,8 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="emv_plugin_ep", targets=["f7"], - requires=["nfc"], - sources=["plugins/supported_cards/emv.c"], + requires=["nfc", "storage"], + sources=["plugins/supported_cards/emv.c", "helpers/nfc_emv_parser.c"], ) App( diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c index 2d76a3fb9..c1320a077 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -4,12 +4,41 @@ #include "nfc/nfc_app_i.h" void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str) { - nfc_render_iso14443_4a_info(data->iso14443_4a_data, format_type, str); - // nfc_render_emv_name(data->emv_application.name, str); - // nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str); - // nfc_render_emv_expired(&data->emv_application, str); + nfc_render_emv_header(str); + nfc_render_emv_uid( + data->iso14443_4a_data->iso14443_3a_data->uid, + data->iso14443_4a_data->iso14443_3a_data->uid_len, + str); - // if(format_type == NfcProtocolFormatTypeFull) nfc_render_emv_extra(data, str); + if(format_type == NfcProtocolFormatTypeFull) nfc_render_emv_extra(data, str); +} + +void nfc_render_emv_header(FuriString* str) { + furi_string_cat_printf(str, "\e#%s\n", "EMV"); +} + +void nfc_render_emv_uid(const uint8_t* uid, const uint8_t uid_len, FuriString* str) { + if(uid_len == 0) return; + + furi_string_cat_printf(str, "UID: "); + + for(uint8_t i = 0; i < uid_len; i++) { + furi_string_cat_printf(str, "%02X ", uid[i]); + } + + furi_string_cat_printf(str, "\n"); +} + +void nfc_render_emv_aid(const uint8_t* uid, const uint8_t uid_len, FuriString* str) { + if(uid_len == 0) return; + + furi_string_cat_printf(str, "UID: "); + + for(uint8_t i = 0; i < uid_len; i++) { + furi_string_cat_printf(str, "%02X ", uid[i]); + } + + furi_string_cat_printf(str, "\n"); } void nfc_render_emv_data(const EmvData* data, FuriString* str) { @@ -42,31 +71,13 @@ void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str) { void nfc_render_emv_currency(uint16_t cur_code, FuriString* str) { if(!cur_code) return; - Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* currency_name = furi_string_alloc(); - if(nfc_emv_parser_get_currency_name(storage, cur_code, currency_name)) { - furi_string_cat_printf(str, "Currency: %s\n", furi_string_get_cstr(currency_name)); - } - furi_string_free(currency_name); - furi_record_close(RECORD_STORAGE); + furi_string_cat_printf(str, "Currency code: %04X\n", cur_code); } void nfc_render_emv_country(uint16_t country_code, FuriString* str) { if(!country_code) return; - Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* country_name = furi_string_alloc(); - if(nfc_emv_parser_get_country_name(storage, country_code, country_name)) { - furi_string_cat_printf(str, "Country: %s\n", furi_string_get_cstr(country_name)); - } - furi_string_free(country_name); - furi_record_close(RECORD_STORAGE); -} -void nfc_render_emv_name(const char* data, FuriString* str) { - if(strlen(data) == 0) return; - furi_string_cat_printf(str, "\e#"); - furi_string_cat(str, data); - furi_string_cat_printf(str, "\n"); + furi_string_cat_printf(str, "Country code: %04X\n", country_code); } void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { @@ -78,18 +89,10 @@ void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { } furi_string_cat_printf(str, "AID: "); - Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* aid_name = furi_string_alloc(); - if(nfc_emv_parser_get_aid_name(storage, apl->aid, len, aid_name)) { - furi_string_cat_printf(str, "%s", furi_string_get_cstr(aid_name)); - } else { - for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]); - } + for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]); furi_string_cat_printf(str, "\n"); - furi_string_free(aid_name); - furi_record_close(RECORD_STORAGE); } static void nfc_render_emv_pin_try_counter(uint8_t counter, FuriString* str) { @@ -171,8 +174,9 @@ void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { } void nfc_render_emv_extra(const EmvData* data, FuriString* str) { + nfc_render_emv_application(&data->emv_application, str); + nfc_render_emv_currency(data->emv_application.currency_code, str); nfc_render_emv_country(data->emv_application.country_code, str); - nfc_render_emv_application(&data->emv_application, str); nfc_render_emv_pin_try_counter(data->emv_application.pin_try_counter, str); } diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h index 80f80d423..855acdc4a 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h @@ -23,4 +23,8 @@ void nfc_render_emv_country(uint16_t country_code, FuriString* str); void nfc_render_emv_currency(uint16_t cur_code, FuriString* str); -void nfc_render_emv_transactions(const EmvApplication* data, FuriString* str); \ No newline at end of file +void nfc_render_emv_transactions(const EmvApplication* data, FuriString* str); + +void nfc_render_emv_uid(const uint8_t* uid, const uint8_t uid_len, FuriString* str); + +void nfc_render_emv_header(FuriString* str); \ No newline at end of file diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index 99842f2d6..f0bdded4a 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -89,20 +89,20 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { furi_string_cat(parsed_data, pan); furi_string_free(pan); - furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X", app.exp_month, app.exp_year); + furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X\n", app.exp_month, app.exp_year); FuriString* str = furi_string_alloc(); bool storage_readed = emv_get_country_name(app.country_code, str); if(storage_readed) - furi_string_cat_printf(parsed_data, "\nCountry: %s", furi_string_get_cstr(str)); + furi_string_cat_printf(parsed_data, "Country: %s\n", furi_string_get_cstr(str)); storage_readed = emv_get_currency_name(app.currency_code, str); if(storage_readed) - furi_string_cat_printf(parsed_data, "\nCurrency: %s", furi_string_get_cstr(str)); + furi_string_cat_printf(parsed_data, "Currency: %s\n", furi_string_get_cstr(str)); if(app.pin_try_counter != 0xFF) - furi_string_cat_printf(str, "\nPIN try left: %d\n", app.pin_try_counter); + furi_string_cat_printf(str, "PIN try left: %d\n", app.pin_try_counter); parsed = true; } while(false); From fee4a5a8f76559b812a443fadb256059c2297ec1 Mon Sep 17 00:00:00 2001 From: Methodius Date: Tue, 30 Jan 2024 02:22:21 +0900 Subject: [PATCH 104/110] EMV save/load dump options added --- .../main/nfc/plugins/supported_cards/emv.c | 4 +- lib/nfc/protocols/emv/emv.c | 89 +++++++++++++++++-- targets/f18/api_symbols.csv | 2 +- targets/f7/api_symbols.csv | 2 +- 4 files changed, 86 insertions(+), 11 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index f0bdded4a..d2cd8c4a7 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -101,8 +101,8 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { if(storage_readed) furi_string_cat_printf(parsed_data, "Currency: %s\n", furi_string_get_cstr(str)); - if(app.pin_try_counter != 0xFF) - furi_string_cat_printf(str, "PIN try left: %d\n", app.pin_try_counter); + // if(app.pin_try_counter != 0xFF) + furi_string_cat_printf(parsed_data, "PIN try left: %d\n", app.pin_try_counter); parsed = true; } while(false); diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index bbeacffb8..4cdacaefe 100644 --- a/lib/nfc/protocols/emv/emv.c +++ b/lib/nfc/protocols/emv/emv.c @@ -1,5 +1,6 @@ //#include "emv_i.h" +#include "flipper_format.h" #include #include "protocols/emv/emv.h" #include @@ -65,19 +66,93 @@ bool emv_verify(EmvData* data, const FuriString* device_type) { bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { furi_assert(data); - UNUSED(data); - UNUSED(ff); - UNUSED(version); - return false; + FuriString* temp_str = furi_string_alloc(); + bool parsed = false; + + do { + // Read ISO14443_4A data + if(!iso14443_4a_load(data->iso14443_4a_data, ff, version)) break; + + EmvApplication* app = &data->emv_application; + + //Read name + if(!flipper_format_read_string(ff, "Name", temp_str)) break; + strcpy(app->name, furi_string_get_cstr(temp_str)); + if(app->name[0] != '\0') app->name_found = true; + + uint32_t pan_len; + if(!flipper_format_read_uint32(ff, "PAN length", &pan_len, 1)) break; + app->pan_len = pan_len; + + if(!flipper_format_read_hex(ff, "PAN", app->pan, pan_len)) break; + + uint32_t aid_len; + if(!flipper_format_read_uint32(ff, "AID length", &aid_len, 1)) break; + app->aid_len = aid_len; + + if(!flipper_format_read_hex(ff, "AID", app->aid, aid_len)) break; + + if(!flipper_format_read_hex(ff, "Country code", (uint8_t*)&app->country_code, 2)) break; + + if(!flipper_format_read_hex(ff, "Currency code", (uint8_t*)&app->currency_code, 2)) break; + + if(!flipper_format_read_hex(ff, "Expiration year", &app->exp_year, 1)) break; + if(!flipper_format_read_hex(ff, "Expiration month", &app->exp_month, 1)) break; + + uint32_t pin_try_counter; + if(!flipper_format_read_uint32(ff, "PIN counter", &pin_try_counter, 1)) break; + app->pin_try_counter = pin_try_counter; + + parsed = true; + } while(false); + + furi_string_free(temp_str); + + return parsed; } bool emv_save(const EmvData* data, FlipperFormat* ff) { furi_assert(data); - UNUSED(data); - UNUSED(ff); - return false; + FuriString* temp_str = furi_string_alloc(); + bool saved = false; + + do { + EmvApplication app = data->emv_application; + if(!iso14443_4a_save(data->iso14443_4a_data, ff)) break; + + if(!flipper_format_write_comment_cstr(ff, "EMV specific data:\n")) break; + + if(!flipper_format_write_string_cstr(ff, "Name", app.name)) break; + + uint32_t pan_len = app.pan_len; + if(!flipper_format_write_uint32(ff, "PAN length", &pan_len, 1)) break; + + if(!flipper_format_write_hex(ff, "PAN", app.pan, pan_len)) break; + + uint32_t aid_len = app.aid_len; + if(!flipper_format_write_uint32(ff, "AID length", &aid_len, 1)) break; + + if(!flipper_format_write_hex(ff, "AID", app.aid, aid_len)) break; + + if(!flipper_format_write_hex(ff, "Country code", (uint8_t*)&app.country_code, 2)) break; + + if(!flipper_format_write_hex(ff, "Currency code", (uint8_t*)&app.currency_code, 2)) break; + + if(!flipper_format_write_hex(ff, "Expiration year", (uint8_t*)&app.exp_year, 1)) break; + + if(!flipper_format_write_hex(ff, "Expiration month", (uint8_t*)&app.exp_month, 1)) break; + + if(!flipper_format_write_uint32(ff, "PIN counter", (uint32_t*)&app.pin_try_counter, 1)) + break; + + saved = true; + } while(false); + + furi_string_free(temp_str); + + return saved; } bool emv_is_equal(const EmvData* data, const EmvData* other) { diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 56e47318e..add27f40a 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,50.2,, +Version,+,53.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 948f957b5..6923b79da 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,52.3,, +Version,+,53.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, From 92a25af3c3d4b9831c53d49c995f00ad16c0b2e9 Mon Sep 17 00:00:00 2001 From: Methodius Date: Tue, 30 Jan 2024 02:37:59 +0900 Subject: [PATCH 105/110] minor parser fixes --- .../main/nfc/plugins/supported_cards/emv.c | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index d2cd8c4a7..ebcc392c8 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -78,18 +78,21 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { else furi_string_cat_printf(parsed_data, "\e#%s\n", "EMV"); - FuriString* pan = furi_string_alloc(); - for(uint8_t i = 0; i < app.pan_len; i += 2) { - furi_string_cat_printf(pan, "%02X%02X ", app.pan[i], app.pan[i + 1]); + if(app.pan_len) { + FuriString* pan = furi_string_alloc(); + for(uint8_t i = 0; i < app.pan_len; i += 2) { + furi_string_cat_printf(pan, "%02X%02X ", app.pan[i], app.pan[i + 1]); + } + + // Cut padding 'F' from card number + size_t end = furi_string_search_rchar(pan, 'F'); + if(end) furi_string_left(pan, end); + furi_string_cat(parsed_data, pan); + furi_string_free(pan); } - // Cut padding 'F' from card number - size_t end = furi_string_search_rchar(pan, 'F'); - if(end) furi_string_left(pan, end); - furi_string_cat(parsed_data, pan); - furi_string_free(pan); - - furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X\n", app.exp_month, app.exp_year); + if(app.exp_month | app.exp_year) + furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X\n", app.exp_month, app.exp_year); FuriString* str = furi_string_alloc(); bool storage_readed = emv_get_country_name(app.country_code, str); @@ -101,8 +104,8 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { if(storage_readed) furi_string_cat_printf(parsed_data, "Currency: %s\n", furi_string_get_cstr(str)); - // if(app.pin_try_counter != 0xFF) - furi_string_cat_printf(parsed_data, "PIN try left: %d\n", app.pin_try_counter); + if(app.pin_try_counter != 0xFF) + furi_string_cat_printf(parsed_data, "PIN try left: %d\n", app.pin_try_counter); parsed = true; } while(false); From 51d8b18f3eaa627e2c9f3c869a6079fc13dd45f6 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Tue, 30 Jan 2024 00:26:16 +0000 Subject: [PATCH 106/110] Read SFI until PAN find * get rid of input result buffers --- lib/nfc/protocols/emv/emv_poller.c | 22 ++++--------------- lib/nfc/protocols/emv/emv_poller_i.c | 6 +++++ lib/nfc/protocols/emv/emv_poller_i.h | 2 -- .../iso14443_4a/iso14443_4a_poller_i.c | 6 +++++ 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c index 7907908fd..6ca21df1c 100644 --- a/lib/nfc/protocols/emv/emv_poller.c +++ b/lib/nfc/protocols/emv/emv_poller.c @@ -6,9 +6,8 @@ #define TAG "EMVPoller" -// SKOLKO????????????????????????????????????????????????????????????????? +// MAX Le is 255 bytes + 2 for CRC #define EMV_BUF_SIZE (512U) -#define EMV_RESULT_BUF_SIZE (512U) typedef NfcCommand (*EmvPollerReadHandler)(EmvPoller* instance); @@ -24,8 +23,6 @@ static EmvPoller* emv_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller) { instance->data = emv_alloc(); instance->tx_buffer = bit_buffer_alloc(EMV_BUF_SIZE); instance->rx_buffer = bit_buffer_alloc(EMV_BUF_SIZE); - instance->input_buffer = bit_buffer_alloc(EMV_BUF_SIZE); - instance->result_buffer = bit_buffer_alloc(EMV_RESULT_BUF_SIZE); instance->state = EmvPollerStateIdle; @@ -44,14 +41,10 @@ static void emv_poller_free(EmvPoller* instance) { emv_free(instance->data); bit_buffer_free(instance->tx_buffer); bit_buffer_free(instance->rx_buffer); - bit_buffer_free(instance->input_buffer); - bit_buffer_free(instance->result_buffer); free(instance); } static NfcCommand emv_poller_handler_idle(EmvPoller* instance) { - bit_buffer_reset(instance->input_buffer); - bit_buffer_reset(instance->result_buffer); bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); @@ -106,21 +99,14 @@ static NfcCommand emv_poller_handler_get_processing_options(EmvPoller* instance) } static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) { - instance->error = emv_poller_read_afl(instance); - - if(instance->error == EmvErrorNone) { - FURI_LOG_D(TAG, "Read files success"); - instance->state = EmvPollerStateReadExtra; - } else { - FURI_LOG_E(TAG, "Failed to read files"); - instance->state = EmvPollerStateReadFailed; - } + emv_poller_read_afl(instance); + emv_poller_read_log_entry(instance); + instance->state = EmvPollerStateReadExtra; return NfcCommandContinue; } static NfcCommand emv_poller_handler_read_extra_data(EmvPoller* instance) { - emv_poller_read_log_entry(instance); emv_poller_get_last_online_atc(instance); emv_poller_get_pin_try_counter(instance); diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 2fbae4fc4..c237125b2 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -619,6 +619,12 @@ EmvError emv_poller_read_afl(EmvPoller* instance) { error = EmvErrorProtocol; FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record); } + + // Some READ RECORD returns 1 byte response 0x12/0x13 (IDK WTF), + // then poller return Timeout to all subsequent requests. + // TODO: remove below lines when it was fixed + if(instance->data->emv_application.pan_len != 0) + return EmvErrorNone; // Card number fetched } } diff --git a/lib/nfc/protocols/emv/emv_poller_i.h b/lib/nfc/protocols/emv/emv_poller_i.h index 620d2f359..704365747 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.h +++ b/lib/nfc/protocols/emv/emv_poller_i.h @@ -35,8 +35,6 @@ struct EmvPoller { EmvData* data; BitBuffer* tx_buffer; BitBuffer* rx_buffer; - BitBuffer* input_buffer; - BitBuffer* result_buffer; EmvPollerEventData emv_event_data; EmvPollerEvent emv_event; NfcGenericEvent general_event; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index b8e2ebda6..2065b81a2 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -103,6 +103,12 @@ Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext( iso14443_4a_get_fwt_fc_max(instance->data)); if(iso14443_3a_error != Iso14443_3aErrorNone) { + FURI_LOG_RAW_T("RAW RX(%d):", bit_buffer_get_size_bytes(instance->rx_buffer)); + for(size_t x = 0; x < bit_buffer_get_size_bytes(instance->rx_buffer); x++) { + FURI_LOG_RAW_T("%02X ", bit_buffer_get_byte(instance->rx_buffer, x)); + } + FURI_LOG_RAW_T("\r\n"); + error = iso14443_4a_process_error(iso14443_3a_error); break; From 872987f002bdd5077dd335783597dbb2ebb1fa69 Mon Sep 17 00:00:00 2001 From: Methodius Date: Tue, 30 Jan 2024 13:50:57 +0900 Subject: [PATCH 107/110] Protocol featore: more info --- applications/main/nfc/helpers/protocol_support/emv/emv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv.c b/applications/main/nfc/helpers/protocol_support/emv/emv.c index 0b60bea6e..e543291cc 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv.c @@ -75,7 +75,7 @@ static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) { // } const NfcProtocolSupportBase nfc_protocol_support_emv = { - .features = NfcProtocolFeatureNone, + .features = NfcProtocolFeatureMoreInfo, .scene_info = { From b0371b3465f2ece7259fad08e6a3daaa5a4b0083 Mon Sep 17 00:00:00 2001 From: Methodius Date: Tue, 30 Jan 2024 16:55:22 +0900 Subject: [PATCH 108/110] metromoney parser balance fix --- applications/main/nfc/plugins/supported_cards/metromoney.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/plugins/supported_cards/metromoney.c b/applications/main/nfc/plugins/supported_cards/metromoney.c index 063f8ffcc..2b33da153 100644 --- a/applications/main/nfc/plugins/supported_cards/metromoney.c +++ b/applications/main/nfc/plugins/supported_cards/metromoney.c @@ -147,7 +147,7 @@ static bool metromoney_parse(const NfcDevice* device, FuriString* parsed_data) { const uint8_t* block_start_ptr = &data->block[start_block_num + ticket_block_number].data[0]; - uint32_t balance = nfc_util_bytes2num_little_endian(block_start_ptr, 4); + uint32_t balance = nfc_util_bytes2num_little_endian(block_start_ptr, 4) - 100; uint32_t balance_lari = balance / 100; uint8_t balance_tetri = balance % 100; From 834c2efb8b5862e4f10a47c331af919818ce8d8e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:24:26 +0300 Subject: [PATCH 109/110] upd changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1a124bf0..23311b809 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ ## New changes +* NFC: EMV parser added (by @Leptopt1los and @wosk | PR #700) +* NFC: Metromoney parser balance fix (by @Leptopt1los | PR #699) * Archive: Fix two filebrowser bugs * SubGHz: Programming mode for Dea Mio (right arrow button) * SubGHz: Keeloq fix emulation for multiple systems and extend add manually support for 2 of them (Dea Mio, Genius Bravo, GSN, Normstahl) @@ -33,7 +35,6 @@

#### Known NFC post-refactor regressions list: - Mifare Mini clones reading is broken (original mini working fine) (OFW) -- EMV simple data parser was removed with protocol with refactoring (OFW) - Option to unlock Slix-L (NFC V) with preset or custom password was removed with refactoring (OFW) - NFC CLI was removed with refactoring (OFW) - Current list of affected apps: https://github.com/xMasterX/all-the-plugins/tree/dev/apps_broken_by_last_refactors From ed3cd21f5ccb4b5696953a6cb879a73f49fb69cf Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 Jan 2024 21:18:27 +0300 Subject: [PATCH 110/110] run fbt format, add smol fix --- .../main/subghz/subghz_last_settings.c | 1 + applications/system/hid_app/views/hid_ptt.c | 730 ++++++++++++------ applications/system/hid_app/views/hid_ptt.h | 2 +- .../system/hid_app/views/hid_ptt_menu.c | 108 +-- .../system/hid_app/views/hid_ptt_menu.h | 12 +- 5 files changed, 546 insertions(+), 307 deletions(-) diff --git a/applications/main/subghz/subghz_last_settings.c b/applications/main/subghz/subghz_last_settings.c index 07bad225d..5dd2680e2 100644 --- a/applications/main/subghz/subghz_last_settings.c +++ b/applications/main/subghz/subghz_last_settings.c @@ -126,6 +126,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count instance->timestamp_file_names = false; instance->external_module_power_amp = false; instance->enable_hopping = false; + instance->delete_old_signals = false; instance->ignore_filter = 0x00; // See bin_raw_value in applications/main/subghz/scenes/subghz_scene_receiver_config.c instance->filter = SubGhzProtocolFlag_Decodable; diff --git a/applications/system/hid_app/views/hid_ptt.c b/applications/system/hid_app/views/hid_ptt.c index 86e9f766f..1d71490a2 100644 --- a/applications/system/hid_app/views/hid_ptt.c +++ b/applications/system/hid_app/views/hid_ptt.c @@ -27,8 +27,8 @@ typedef struct { bool ptt_pressed; bool mic_pressed; bool connected; - FuriString *os; - FuriString *app; + FuriString* os; + FuriString* app; size_t osIndex; size_t appIndex; size_t window_position; @@ -65,391 +65,454 @@ static void hid_ptt_stop_ptt_meet_zoom(HidPushToTalk* hid_ptt) { hid_hal_keyboard_release(hid_ptt->hid, HID_KEYBOARD_SPACEBAR); } static void hid_ptt_trigger_mute_macos_meet(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_D); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_D); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_D); } static void hid_ptt_trigger_mute_linux_meet(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_D); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_D); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_D); } static void hid_ptt_trigger_camera_macos_meet(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_E); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_E); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_E); } static void hid_ptt_trigger_camera_linux_meet(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_E); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_E ); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_E); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_E); } static void hid_ptt_trigger_hand_macos_meet(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL |HID_KEYBOARD_H); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL |HID_KEYBOARD_H); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL | HID_KEYBOARD_H); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL | HID_KEYBOARD_H); } static void hid_ptt_trigger_hand_linux_meet(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT |HID_KEYBOARD_H); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT |HID_KEYBOARD_H); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT | HID_KEYBOARD_H); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT | HID_KEYBOARD_H); } static void hid_ptt_trigger_mute_macos_zoom(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A); } static void hid_ptt_trigger_mute_linux_zoom(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_A); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_A); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_A); } static void hid_ptt_trigger_camera_macos_zoom(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); } static void hid_ptt_trigger_camera_linux_zoom(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_V); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_V); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_V); } static void hid_ptt_trigger_hand_zoom(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_Y); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_Y); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_Y); } // this one is widely used across different apps static void hid_ptt_trigger_cmd_shift_m(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); } // Hangouts HidPushToTalkAppIndexGoogleHangouts static void hid_ptt_trigger_mute_macos_hangouts(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_D); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_D); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_D); } static void hid_ptt_trigger_mute_linux_hangouts(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_D); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_D); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_D); } static void hid_ptt_trigger_camera_macos_hangouts(HidPushToTalk* hid_ptt) { // and hand in teams - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_E); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_E); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_E); } static void hid_ptt_trigger_camera_linux_hangouts(HidPushToTalk* hid_ptt) { // and hand in teams - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_E); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_E); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_E); } // Signal static void hid_ptt_trigger_mute_signal(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); } static void hid_ptt_trigger_camera_signal(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); } // skype static void hid_ptt_trigger_mute_linux_skype(HidPushToTalk* hid_ptt) { // and webex - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M); } static void hid_ptt_trigger_camera_macos_skype(HidPushToTalk* hid_ptt) { // and hand in teams - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K); } static void hid_ptt_trigger_camera_linux_skype(HidPushToTalk* hid_ptt) { // and hand in teams - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K); + hid_hal_keyboard_release( + hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K); } // slack call static void hid_ptt_trigger_mute_slack_call(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, HID_KEYBOARD_M); + hid_hal_keyboard_press(hid_ptt->hid, HID_KEYBOARD_M); hid_hal_keyboard_release(hid_ptt->hid, HID_KEYBOARD_M); } static void hid_ptt_trigger_camera_slack_call(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, HID_KEYBOARD_V); + hid_hal_keyboard_press(hid_ptt->hid, HID_KEYBOARD_V); hid_hal_keyboard_release(hid_ptt->hid, HID_KEYBOARD_V); } // slack hubble static void hid_ptt_trigger_mute_macos_slack_hubble(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_SPACEBAR); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_SPACEBAR); + hid_hal_keyboard_press( + hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_SPACEBAR); + hid_hal_keyboard_release( + hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_SPACEBAR); } static void hid_ptt_trigger_mute_linux_slack_hubble(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_SPACEBAR); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_SPACEBAR); + hid_hal_keyboard_press( + hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_SPACEBAR); + hid_hal_keyboard_release( + hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_SPACEBAR); } // discord static void hid_ptt_trigger_mute_macos_discord(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_press( + hid_ptt->hid, + KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | + HID_KEYBOARD_M); + hid_hal_keyboard_release( + hid_ptt->hid, + KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | + HID_KEYBOARD_M); } static void hid_ptt_start_ptt_macos_discord(HidPushToTalk* hid_ptt) { // and TeamSpeak - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_P); + hid_hal_keyboard_press( + hid_ptt->hid, + KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | + HID_KEYBOARD_P); } static void hid_ptt_stop_ptt_macos_discord(HidPushToTalk* hid_ptt) { // and TeamSpeak - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_P); + hid_hal_keyboard_release( + hid_ptt->hid, + KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | + HID_KEYBOARD_P); } static void hid_ptt_trigger_mute_linux_discord(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_press( + hid_ptt->hid, + KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | + HID_KEYBOARD_M); + hid_hal_keyboard_release( + hid_ptt->hid, + KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | + HID_KEYBOARD_M); } static void hid_ptt_start_ptt_linux_discord(HidPushToTalk* hid_ptt) { // and TeamSpeak - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_P); + hid_hal_keyboard_press( + hid_ptt->hid, + KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | + HID_KEYBOARD_P); } static void hid_ptt_stop_ptt_linux_discord(HidPushToTalk* hid_ptt) { // and TeamSpeak - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_P); + hid_hal_keyboard_release( + hid_ptt->hid, + KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_LEFT_SHIFT | + HID_KEYBOARD_P); } // teamspeak static void hid_ptt_trigger_mute_macos_teamspeak(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_M); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_press( + hid_ptt->hid, + KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | + HID_KEYBOARD_M); + hid_hal_keyboard_release( + hid_ptt->hid, + KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | + HID_KEYBOARD_M); } static void hid_ptt_start_ptt_macos_teamspeak(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_P); + hid_hal_keyboard_press( + hid_ptt->hid, + KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | + HID_KEYBOARD_P); } static void hid_ptt_stop_ptt_macos_teamspeak(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_P); + hid_hal_keyboard_release( + hid_ptt->hid, + KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_GUI | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | + HID_KEYBOARD_P); } static void hid_ptt_trigger_mute_linux_teamspeak(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_M); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_press( + hid_ptt->hid, + KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | + HID_KEYBOARD_M); + hid_hal_keyboard_release( + hid_ptt->hid, + KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | + HID_KEYBOARD_M); } static void hid_ptt_start_ptt_linux_teamspeak(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_P); + hid_hal_keyboard_press( + hid_ptt->hid, + KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | + HID_KEYBOARD_P); } static void hid_ptt_stop_ptt_linux_teamspeak(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_P); + hid_hal_keyboard_release( + hid_ptt->hid, + KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_CTRL | KEY_MOD_RIGHT_ALT | KEY_MOD_RIGHT_SHIFT | + HID_KEYBOARD_P); } // teams static void hid_ptt_start_ptt_macos_teams(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI|HID_KEYBOARD_SPACEBAR); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_SPACEBAR); } static void hid_ptt_start_ptt_linux_teams(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL|HID_KEYBOARD_SPACEBAR); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_SPACEBAR); } static void hid_ptt_stop_ptt_macos_teams(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI|HID_KEYBOARD_SPACEBAR); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_SPACEBAR); } static void hid_ptt_stop_ptt_linux_teams(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL|HID_KEYBOARD_SPACEBAR); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_SPACEBAR); } static void hid_ptt_trigger_mute_linux_teams(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_release( + hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); } static void hid_ptt_trigger_camera_macos_teams(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_O); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_O); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_O); } static void hid_ptt_trigger_camera_linux_teams(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_O); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT |HID_KEYBOARD_O); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_O); + hid_hal_keyboard_release( + hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_O); } // Jamulus static void hid_ptt_trigger_mute_jamulus(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_M); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_M); hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_M); } // webex - static void hid_ptt_trigger_camera_webex(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); + hid_hal_keyboard_release( + hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); } static void hid_ptt_trigger_hand_macos_webex(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_R); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_R); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_R); + hid_hal_keyboard_release( + hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_R); } static void hid_ptt_trigger_hand_linux_webex(HidPushToTalk* hid_ptt) { - hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_R); - hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_R); + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_R); + hid_hal_keyboard_release( + hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_R); } -static void hid_ptt_menu_callback(void* context, uint32_t osIndex, FuriString* osLabel, uint32_t appIndex, FuriString* appLabel) { +static void hid_ptt_menu_callback( + void* context, + uint32_t osIndex, + FuriString* osLabel, + uint32_t appIndex, + FuriString* appLabel) { furi_assert(context); HidPushToTalk* hid_ptt = context; - with_view_model( - hid_ptt->view, HidPushToTalkModel * model, { + with_view_model( + hid_ptt->view, + HidPushToTalkModel * model, + { furi_string_set(model->os, osLabel); furi_string_set(model->app, appLabel); model->osIndex = osIndex; model->appIndex = appIndex; - model->callback_trigger_mute = NULL; + model->callback_trigger_mute = NULL; model->callback_trigger_camera = NULL; - model->callback_trigger_hand = NULL; - model->callback_start_ptt = NULL; - model->callback_stop_ptt = NULL; + model->callback_trigger_hand = NULL; + model->callback_start_ptt = NULL; + model->callback_stop_ptt = NULL; FURI_LOG_E(TAG, "appIndex: %lu", appIndex); if(osIndex == HidPushToTalkMacOS) { switch(appIndex) { case HidPushToTalkAppIndexDiscord: - model->callback_trigger_mute = hid_ptt_trigger_mute_macos_discord; - model->callback_start_ptt = hid_ptt_start_ptt_macos_discord; - model->callback_stop_ptt = hid_ptt_stop_ptt_macos_discord; + model->callback_trigger_mute = hid_ptt_trigger_mute_macos_discord; + model->callback_start_ptt = hid_ptt_start_ptt_macos_discord; + model->callback_stop_ptt = hid_ptt_stop_ptt_macos_discord; break; case HidPushToTalkAppIndexFaceTime: - model->callback_trigger_mute = hid_ptt_trigger_cmd_shift_m; - model->callback_start_ptt = hid_ptt_trigger_cmd_shift_m; - model->callback_stop_ptt = hid_ptt_trigger_cmd_shift_m; + model->callback_trigger_mute = hid_ptt_trigger_cmd_shift_m; + model->callback_start_ptt = hid_ptt_trigger_cmd_shift_m; + model->callback_stop_ptt = hid_ptt_trigger_cmd_shift_m; break; case HidPushToTalkAppIndexGoogleHangouts: - model->callback_trigger_mute = hid_ptt_trigger_mute_macos_hangouts; + model->callback_trigger_mute = hid_ptt_trigger_mute_macos_hangouts; model->callback_trigger_camera = hid_ptt_trigger_camera_macos_hangouts; - model->callback_start_ptt = hid_ptt_trigger_mute_macos_hangouts; - model->callback_stop_ptt = hid_ptt_trigger_mute_macos_hangouts; + model->callback_start_ptt = hid_ptt_trigger_mute_macos_hangouts; + model->callback_stop_ptt = hid_ptt_trigger_mute_macos_hangouts; break; case HidPushToTalkAppIndexGoogleMeet: - model->callback_trigger_mute = hid_ptt_trigger_mute_macos_meet; + model->callback_trigger_mute = hid_ptt_trigger_mute_macos_meet; model->callback_trigger_camera = hid_ptt_trigger_camera_macos_meet; - model->callback_trigger_hand = hid_ptt_trigger_hand_macos_meet; - model->callback_start_ptt = hid_ptt_start_ptt_meet_zoom; - model->callback_stop_ptt = hid_ptt_stop_ptt_meet_zoom; + model->callback_trigger_hand = hid_ptt_trigger_hand_macos_meet; + model->callback_start_ptt = hid_ptt_start_ptt_meet_zoom; + model->callback_stop_ptt = hid_ptt_stop_ptt_meet_zoom; break; case HidPushToTalkAppIndexJamulus: - model->callback_trigger_mute = hid_ptt_trigger_mute_jamulus; - model->callback_start_ptt = hid_ptt_trigger_mute_jamulus; - model->callback_stop_ptt = hid_ptt_trigger_mute_jamulus; + model->callback_trigger_mute = hid_ptt_trigger_mute_jamulus; + model->callback_start_ptt = hid_ptt_trigger_mute_jamulus; + model->callback_stop_ptt = hid_ptt_trigger_mute_jamulus; break; case HidPushToTalkAppIndexTeams: - model->callback_trigger_mute = hid_ptt_trigger_cmd_shift_m; + model->callback_trigger_mute = hid_ptt_trigger_cmd_shift_m; model->callback_trigger_camera = hid_ptt_trigger_camera_macos_teams; - model->callback_trigger_hand = hid_ptt_trigger_camera_macos_skype; - model->callback_start_ptt = hid_ptt_start_ptt_macos_teams; - model->callback_stop_ptt = hid_ptt_stop_ptt_macos_teams; + model->callback_trigger_hand = hid_ptt_trigger_camera_macos_skype; + model->callback_start_ptt = hid_ptt_start_ptt_macos_teams; + model->callback_stop_ptt = hid_ptt_stop_ptt_macos_teams; break; case HidPushToTalkAppIndexTeamSpeak: - model->callback_trigger_mute = hid_ptt_trigger_mute_macos_teamspeak; - model->callback_start_ptt = hid_ptt_start_ptt_macos_teamspeak; - model->callback_stop_ptt = hid_ptt_stop_ptt_macos_teamspeak; + model->callback_trigger_mute = hid_ptt_trigger_mute_macos_teamspeak; + model->callback_start_ptt = hid_ptt_start_ptt_macos_teamspeak; + model->callback_stop_ptt = hid_ptt_stop_ptt_macos_teamspeak; break; case HidPushToTalkAppIndexSignal: - model->callback_trigger_mute = hid_ptt_trigger_mute_signal; + model->callback_trigger_mute = hid_ptt_trigger_mute_signal; model->callback_trigger_camera = hid_ptt_trigger_camera_signal; - model->callback_start_ptt = hid_ptt_trigger_mute_signal; - model->callback_stop_ptt = hid_ptt_trigger_mute_signal; + model->callback_start_ptt = hid_ptt_trigger_mute_signal; + model->callback_stop_ptt = hid_ptt_trigger_mute_signal; break; case HidPushToTalkAppIndexSkype: - model->callback_trigger_mute = hid_ptt_trigger_cmd_shift_m; + model->callback_trigger_mute = hid_ptt_trigger_cmd_shift_m; model->callback_trigger_camera = hid_ptt_trigger_camera_macos_skype; - model->callback_start_ptt = hid_ptt_trigger_cmd_shift_m; - model->callback_stop_ptt = hid_ptt_trigger_cmd_shift_m; + model->callback_start_ptt = hid_ptt_trigger_cmd_shift_m; + model->callback_stop_ptt = hid_ptt_trigger_cmd_shift_m; break; case HidPushToTalkAppIndexSlackCall: - model->callback_trigger_mute = hid_ptt_trigger_mute_slack_call; + model->callback_trigger_mute = hid_ptt_trigger_mute_slack_call; model->callback_trigger_camera = hid_ptt_trigger_camera_slack_call; - model->callback_start_ptt = hid_ptt_trigger_mute_slack_call; - model->callback_stop_ptt = hid_ptt_trigger_mute_slack_call; + model->callback_start_ptt = hid_ptt_trigger_mute_slack_call; + model->callback_stop_ptt = hid_ptt_trigger_mute_slack_call; break; case HidPushToTalkAppIndexSlackHubble: - model->callback_trigger_mute = hid_ptt_trigger_mute_macos_slack_hubble; - model->callback_start_ptt = hid_ptt_trigger_mute_macos_slack_hubble; - model->callback_stop_ptt = hid_ptt_trigger_mute_macos_slack_hubble; + model->callback_trigger_mute = hid_ptt_trigger_mute_macos_slack_hubble; + model->callback_start_ptt = hid_ptt_trigger_mute_macos_slack_hubble; + model->callback_stop_ptt = hid_ptt_trigger_mute_macos_slack_hubble; break; case HidPushToTalkAppIndexWebex: - model->callback_trigger_mute = hid_ptt_trigger_cmd_shift_m; + model->callback_trigger_mute = hid_ptt_trigger_cmd_shift_m; model->callback_trigger_camera = hid_ptt_trigger_camera_webex; - model->callback_trigger_hand = hid_ptt_trigger_hand_macos_webex; - model->callback_start_ptt = hid_ptt_trigger_cmd_shift_m; - model->callback_stop_ptt = hid_ptt_trigger_cmd_shift_m; + model->callback_trigger_hand = hid_ptt_trigger_hand_macos_webex; + model->callback_start_ptt = hid_ptt_trigger_cmd_shift_m; + model->callback_stop_ptt = hid_ptt_trigger_cmd_shift_m; break; case HidPushToTalkAppIndexZoom: - model->callback_trigger_mute = hid_ptt_trigger_mute_macos_zoom; + model->callback_trigger_mute = hid_ptt_trigger_mute_macos_zoom; model->callback_trigger_camera = hid_ptt_trigger_camera_macos_zoom; - model->callback_trigger_hand = hid_ptt_trigger_hand_zoom; - model->callback_start_ptt = hid_ptt_start_ptt_meet_zoom; - model->callback_stop_ptt = hid_ptt_stop_ptt_meet_zoom; + model->callback_trigger_hand = hid_ptt_trigger_hand_zoom; + model->callback_start_ptt = hid_ptt_start_ptt_meet_zoom; + model->callback_stop_ptt = hid_ptt_stop_ptt_meet_zoom; break; } - } else if (osIndex == HidPushToTalkLinux) { + } else if(osIndex == HidPushToTalkLinux) { switch(appIndex) { case HidPushToTalkAppIndexDiscord: - model->callback_trigger_mute = hid_ptt_trigger_mute_linux_discord; - model->callback_start_ptt = hid_ptt_start_ptt_linux_discord; - model->callback_stop_ptt = hid_ptt_stop_ptt_linux_discord; + model->callback_trigger_mute = hid_ptt_trigger_mute_linux_discord; + model->callback_start_ptt = hid_ptt_start_ptt_linux_discord; + model->callback_stop_ptt = hid_ptt_stop_ptt_linux_discord; break; case HidPushToTalkAppIndexGoogleHangouts: - model->callback_trigger_mute = hid_ptt_trigger_mute_linux_hangouts; + model->callback_trigger_mute = hid_ptt_trigger_mute_linux_hangouts; model->callback_trigger_camera = hid_ptt_trigger_camera_linux_hangouts; - model->callback_start_ptt = hid_ptt_trigger_mute_linux_hangouts; - model->callback_stop_ptt = hid_ptt_trigger_mute_linux_hangouts; + model->callback_start_ptt = hid_ptt_trigger_mute_linux_hangouts; + model->callback_stop_ptt = hid_ptt_trigger_mute_linux_hangouts; break; case HidPushToTalkAppIndexGoogleMeet: - model->callback_trigger_mute = hid_ptt_trigger_mute_linux_meet; + model->callback_trigger_mute = hid_ptt_trigger_mute_linux_meet; model->callback_trigger_camera = hid_ptt_trigger_camera_linux_meet; - model->callback_trigger_hand = hid_ptt_trigger_hand_linux_meet; - model->callback_start_ptt = hid_ptt_start_ptt_meet_zoom; - model->callback_stop_ptt = hid_ptt_stop_ptt_meet_zoom; + model->callback_trigger_hand = hid_ptt_trigger_hand_linux_meet; + model->callback_start_ptt = hid_ptt_start_ptt_meet_zoom; + model->callback_stop_ptt = hid_ptt_stop_ptt_meet_zoom; break; case HidPushToTalkAppIndexJamulus: - model->callback_trigger_mute = hid_ptt_trigger_mute_jamulus; - model->callback_start_ptt = hid_ptt_trigger_mute_jamulus; - model->callback_stop_ptt = hid_ptt_trigger_mute_jamulus; + model->callback_trigger_mute = hid_ptt_trigger_mute_jamulus; + model->callback_start_ptt = hid_ptt_trigger_mute_jamulus; + model->callback_stop_ptt = hid_ptt_trigger_mute_jamulus; break; case HidPushToTalkAppIndexTeams: - model->callback_trigger_mute = hid_ptt_trigger_mute_linux_teams; + model->callback_trigger_mute = hid_ptt_trigger_mute_linux_teams; model->callback_trigger_camera = hid_ptt_trigger_camera_linux_teams; - model->callback_trigger_hand = hid_ptt_trigger_camera_linux_skype; - model->callback_start_ptt = hid_ptt_start_ptt_linux_teams; - model->callback_stop_ptt = hid_ptt_stop_ptt_linux_teams; + model->callback_trigger_hand = hid_ptt_trigger_camera_linux_skype; + model->callback_start_ptt = hid_ptt_start_ptt_linux_teams; + model->callback_stop_ptt = hid_ptt_stop_ptt_linux_teams; break; case HidPushToTalkAppIndexTeamSpeak: - model->callback_trigger_mute = hid_ptt_trigger_mute_linux_teamspeak; - model->callback_start_ptt = hid_ptt_start_ptt_linux_teamspeak; - model->callback_stop_ptt = hid_ptt_stop_ptt_linux_teamspeak; + model->callback_trigger_mute = hid_ptt_trigger_mute_linux_teamspeak; + model->callback_start_ptt = hid_ptt_start_ptt_linux_teamspeak; + model->callback_stop_ptt = hid_ptt_stop_ptt_linux_teamspeak; break; case HidPushToTalkAppIndexSignal: - model->callback_trigger_mute = hid_ptt_trigger_mute_signal; + model->callback_trigger_mute = hid_ptt_trigger_mute_signal; model->callback_trigger_camera = hid_ptt_trigger_camera_signal; - model->callback_start_ptt = hid_ptt_trigger_mute_signal; - model->callback_stop_ptt = hid_ptt_trigger_mute_signal; + model->callback_start_ptt = hid_ptt_trigger_mute_signal; + model->callback_stop_ptt = hid_ptt_trigger_mute_signal; break; case HidPushToTalkAppIndexSkype: - model->callback_trigger_mute = hid_ptt_trigger_mute_linux_skype; + model->callback_trigger_mute = hid_ptt_trigger_mute_linux_skype; model->callback_trigger_camera = hid_ptt_trigger_camera_linux_skype; - model->callback_start_ptt = hid_ptt_trigger_mute_linux_skype; - model->callback_stop_ptt = hid_ptt_trigger_mute_linux_skype; + model->callback_start_ptt = hid_ptt_trigger_mute_linux_skype; + model->callback_stop_ptt = hid_ptt_trigger_mute_linux_skype; break; case HidPushToTalkAppIndexSlackCall: - model->callback_trigger_mute = hid_ptt_trigger_mute_slack_call; + model->callback_trigger_mute = hid_ptt_trigger_mute_slack_call; model->callback_trigger_camera = hid_ptt_trigger_camera_slack_call; - model->callback_start_ptt = hid_ptt_trigger_mute_slack_call; - model->callback_stop_ptt = hid_ptt_trigger_mute_slack_call; + model->callback_start_ptt = hid_ptt_trigger_mute_slack_call; + model->callback_stop_ptt = hid_ptt_trigger_mute_slack_call; break; case HidPushToTalkAppIndexSlackHubble: - model->callback_trigger_mute = hid_ptt_trigger_mute_linux_slack_hubble; - model->callback_start_ptt = hid_ptt_trigger_mute_linux_slack_hubble; - model->callback_stop_ptt = hid_ptt_trigger_mute_linux_slack_hubble; + model->callback_trigger_mute = hid_ptt_trigger_mute_linux_slack_hubble; + model->callback_start_ptt = hid_ptt_trigger_mute_linux_slack_hubble; + model->callback_stop_ptt = hid_ptt_trigger_mute_linux_slack_hubble; break; case HidPushToTalkAppIndexZoom: - model->callback_trigger_mute = hid_ptt_trigger_mute_linux_zoom; + model->callback_trigger_mute = hid_ptt_trigger_mute_linux_zoom; model->callback_trigger_camera = hid_ptt_trigger_camera_linux_zoom; - model->callback_trigger_hand = hid_ptt_trigger_hand_zoom; - model->callback_start_ptt = hid_ptt_start_ptt_meet_zoom; - model->callback_stop_ptt = hid_ptt_stop_ptt_meet_zoom; + model->callback_trigger_hand = hid_ptt_trigger_hand_zoom; + model->callback_start_ptt = hid_ptt_start_ptt_meet_zoom; + model->callback_stop_ptt = hid_ptt_stop_ptt_meet_zoom; break; case HidPushToTalkAppIndexWebex: - model->callback_trigger_mute = hid_ptt_trigger_mute_linux_skype; + model->callback_trigger_mute = hid_ptt_trigger_mute_linux_skype; model->callback_trigger_camera = hid_ptt_trigger_camera_webex; - model->callback_trigger_hand = hid_ptt_trigger_hand_linux_webex; - model->callback_start_ptt = hid_ptt_trigger_mute_linux_skype; - model->callback_stop_ptt = hid_ptt_trigger_mute_linux_skype; + model->callback_trigger_hand = hid_ptt_trigger_hand_linux_webex; + model->callback_start_ptt = hid_ptt_trigger_mute_linux_skype; + model->callback_stop_ptt = hid_ptt_trigger_mute_linux_skype; break; } } - char *app_specific_help = ""; + char* app_specific_help = ""; switch(appIndex) { case HidPushToTalkAppIndexGoogleMeet: app_specific_help = "Google Meet:\n" "This feature is off by default in your audio settings " "and may not work for Windows users who use their screen " - "reader. In this situation, the spacebar performs a different action.\n\n" - ; + "reader. In this situation, the spacebar performs a different action.\n\n"; break; case HidPushToTalkAppIndexDiscord: app_specific_help = @@ -458,36 +521,36 @@ static void hid_ptt_menu_callback(void* context, uint32_t osIndex, FuriString* o "check the box next to Push to Talk.\n" "2. Scroll down to SHORTCUT, click Record Keybinder.\n" "3. Press PTT in the app to bind it." - "4. Go to Keybinds and assign mute button.\n\n" - ; + "4. Go to Keybinds and assign mute button.\n\n"; break; case HidPushToTalkAppIndexTeamSpeak: - app_specific_help = - "TeamSpeak:\n" - "To make keys working bind them in TeamSpeak settings.\n\n" - ; + app_specific_help = "TeamSpeak:\n" + "To make keys working bind them in TeamSpeak settings.\n\n"; break; case HidPushToTalkAppIndexTeams: app_specific_help = "Teams:\n" - "Go to Settings > Privacy. Make sure Keyboard shortcut to unmute is toggled on.\n\n" - ; + "Go to Settings > Privacy. Make sure Keyboard shortcut to unmute is toggled on.\n\n"; break; } - - FuriString *msg = furi_string_alloc(); - furi_string_cat_printf(msg, - "%sGeneral:\n" - "To operate properly flipper microphone " - "status must be in sync with your computer.\n" - "Hold > to change mic status.\n" - "Hold < to open this help.\n" - "Press BACK to switch mic on/off.\n" - "Hold 'o' for PTT mode (mic will be off once you release 'o')\n" - "Hold BACK to exit.", app_specific_help); - widget_add_text_scroll_element(hid_ptt->help, 0, 0, 128, 64, furi_string_get_cstr(msg)); + + FuriString* msg = furi_string_alloc(); + furi_string_cat_printf( + msg, + "%sGeneral:\n" + "To operate properly flipper microphone " + "status must be in sync with your computer.\n" + "Hold > to change mic status.\n" + "Hold < to open this help.\n" + "Press BACK to switch mic on/off.\n" + "Hold 'o' for PTT mode (mic will be off once you release 'o')\n" + "Hold BACK to exit.", + app_specific_help); + widget_add_text_scroll_element( + hid_ptt->help, 0, 0, 128, 64, furi_string_get_cstr(msg)); furi_string_free(msg); - }, true); + }, + true); view_dispatcher_switch_to_view(hid_ptt->hid->view_dispatcher, HidViewPushToTalk); } @@ -500,8 +563,9 @@ static void hid_ptt_draw_text_centered(Canvas* canvas, uint8_t y, FuriString* st FuriString* disp_str; disp_str = furi_string_alloc_set(str); elements_string_fit_width(canvas, disp_str, canvas_width(canvas)); - uint8_t x_pos = (canvas_width(canvas) - canvas_string_width(canvas,furi_string_get_cstr(disp_str))) / 2; - canvas_draw_str(canvas,x_pos,y,furi_string_get_cstr(disp_str)); + uint8_t x_pos = + (canvas_width(canvas) - canvas_string_width(canvas, furi_string_get_cstr(disp_str))) / 2; + canvas_draw_str(canvas, x_pos, y, furi_string_get_cstr(disp_str)); furi_string_free(disp_str); } @@ -523,7 +587,7 @@ static void hid_ptt_draw_callback(Canvas* canvas, void* context) { canvas_set_font(canvas, FontSecondary); hid_ptt_draw_text_centered(canvas, 73, model->app); hid_ptt_draw_text_centered(canvas, 84, model->os); - + // Help label canvas_draw_icon(canvas, 0, 88, &I_Help_top_64x17); canvas_draw_line(canvas, 4, 105, 4, 114); @@ -533,7 +597,6 @@ static void hid_ptt_draw_callback(Canvas* canvas, void* context) { canvas_draw_icon(canvas, 34, 108, &I_for_help_27x5); canvas_draw_icon(canvas, 0, 115, &I_Help_exit_64x9); canvas_draw_icon(canvas, 24, 115, &I_BtnBackV_9x9); - const uint8_t x_1 = 0; const uint8_t x_2 = x_1 + 19 + 4; @@ -542,7 +605,7 @@ static void hid_ptt_draw_callback(Canvas* canvas, void* context) { const uint8_t y_1 = 3; const uint8_t y_2 = y_1 + 19; const uint8_t y_3 = y_2 + 19; - + // Up canvas_draw_icon(canvas, x_2, y_1, &I_Button_18x18); if(model->up_pressed) { @@ -563,11 +626,11 @@ static void hid_ptt_draw_callback(Canvas* canvas, void* context) { // Left / Help canvas_draw_icon(canvas, x_1, y_2, &I_Button_18x18); - if(model->left_pressed) { + if(model->left_pressed) { elements_slightly_rounded_box(canvas, x_1 + 3, y_2 + 2, 13, 13); canvas_set_color(canvas, ColorWhite); } - if (model->callback_trigger_hand) { + if(model->callback_trigger_hand) { canvas_draw_icon(canvas, x_1 + 4, y_2 + 3, &I_Hand_8x10); } else { canvas_draw_icon(canvas, x_1 + 2, y_2 + 1, &I_BrokenButton_15x15); @@ -580,19 +643,18 @@ static void hid_ptt_draw_callback(Canvas* canvas, void* context) { elements_slightly_rounded_box(canvas, x_3 + 3, y_2 + 2, 13, 13); canvas_set_color(canvas, ColorWhite); } - if (model->callback_trigger_camera) { + if(model->callback_trigger_camera) { hid_ptt_draw_camera(canvas, x_3 + 4, y_2 + 5); } else { canvas_draw_icon(canvas, x_3 + 2, y_2 + 1, &I_BrokenButton_15x15); } canvas_set_color(canvas, ColorBlack); - // Back / Mic const uint8_t x_mic = x_3; canvas_draw_icon(canvas, x_mic, 0, &I_RoundButtonUnpressed_16x16); - - if (!(!model->muted || (model->ptt_pressed))) { + + if(!(!model->muted || (model->ptt_pressed))) { // show muted if(model->mic_pressed) { // canvas_draw_icon(canvas, x_mic + 1, 0, &I_MicrophonePressedCrossed_15x15); @@ -614,19 +676,21 @@ static void hid_ptt_draw_callback(Canvas* canvas, void* context) { const uint8_t x_ptt_margin = 4; const uint8_t x_ptt_width = 17; const uint8_t x_ptt = x_1 + 19; - canvas_draw_icon(canvas, x_ptt , y_2 , &I_BtnFrameLeft_3x18); - canvas_draw_icon(canvas, x_ptt + x_ptt_width + 3 + x_ptt_margin, y_2 , &I_BtnFrameRight_2x18); - canvas_draw_line(canvas, x_ptt + 3 , y_2 , x_ptt + x_ptt_width + 2 + x_ptt_margin, y_2); - canvas_draw_line(canvas, x_ptt + 3 , y_2 + 16, x_ptt + x_ptt_width + 2 + x_ptt_margin, y_2 + 16); - canvas_draw_line(canvas, x_ptt + 3 , y_2 + 17, x_ptt + x_ptt_width + 2 + x_ptt_margin, y_2 + 17); + canvas_draw_icon(canvas, x_ptt, y_2, &I_BtnFrameLeft_3x18); + canvas_draw_icon(canvas, x_ptt + x_ptt_width + 3 + x_ptt_margin, y_2, &I_BtnFrameRight_2x18); + canvas_draw_line(canvas, x_ptt + 3, y_2, x_ptt + x_ptt_width + 2 + x_ptt_margin, y_2); + canvas_draw_line( + canvas, x_ptt + 3, y_2 + 16, x_ptt + x_ptt_width + 2 + x_ptt_margin, y_2 + 16); + canvas_draw_line( + canvas, x_ptt + 3, y_2 + 17, x_ptt + x_ptt_width + 2 + x_ptt_margin, y_2 + 17); - - if (model->ptt_pressed) { + if(model->ptt_pressed) { elements_slightly_rounded_box(canvas, x_ptt + 3, y_2 + 2, x_ptt_width + x_ptt_margin, 13); canvas_set_color(canvas, ColorWhite); } canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, x_ptt + 2 + x_ptt_margin / 2, y_2 + 13, AlignLeft, AlignBottom, "PTT"); + elements_multiline_text_aligned( + canvas, x_ptt + 2 + x_ptt_margin / 2, y_2 + 13, AlignLeft, AlignBottom, "PTT"); canvas_set_font(canvas, FontSecondary); canvas_set_color(canvas, ColorBlack); } @@ -649,8 +713,8 @@ static void hid_ptt_process(HidPushToTalk* hid_ptt, InputEvent* event) { model->right_pressed = true; } else if(event->key == InputKeyOk) { model->ptt_pressed = true; - if (!model->mic_pressed && model->muted){ - model->callback_start_ptt ? model->callback_start_ptt(hid_ptt):0; + if(!model->mic_pressed && model->muted) { + model->callback_start_ptt ? model->callback_start_ptt(hid_ptt) : 0; } } else if(event->key == InputKeyBack) { model->mic_pressed = true; @@ -658,12 +722,12 @@ static void hid_ptt_process(HidPushToTalk* hid_ptt, InputEvent* event) { } else if(event->type == InputTypeRelease) { if(event->key == InputKeyUp) { model->up_pressed = false; - if (!model->ptt_pressed){ + if(!model->ptt_pressed) { hid_hal_consumer_key_release(hid_ptt->hid, HID_CONSUMER_VOLUME_INCREMENT); } } else if(event->key == InputKeyDown) { model->down_pressed = false; - if (!model->ptt_pressed){ + if(!model->ptt_pressed) { hid_hal_consumer_key_release(hid_ptt->hid, HID_CONSUMER_VOLUME_DECREMENT); } } else if(event->key == InputKeyLeft) { @@ -674,10 +738,11 @@ static void hid_ptt_process(HidPushToTalk* hid_ptt, InputEvent* event) { } else if(event->key == InputKeyOk) { model->ptt_pressed = false; if(!model->mic_pressed) { - if (model->muted) { - model->callback_stop_ptt ? model->callback_stop_ptt(hid_ptt):0; + if(model->muted) { + model->callback_stop_ptt ? model->callback_stop_ptt(hid_ptt) : 0; } else { - model->callback_trigger_mute ? model->callback_trigger_mute(hid_ptt):0; + model->callback_trigger_mute ? model->callback_trigger_mute(hid_ptt) : + 0; model->muted = true; } } @@ -685,13 +750,13 @@ static void hid_ptt_process(HidPushToTalk* hid_ptt, InputEvent* event) { model->mic_pressed = false; } } else if(event->type == InputTypeShort && !model->ptt_pressed) { - if(event->key == InputKeyBack ) { // no changes if PTT is pressed + if(event->key == InputKeyBack) { // no changes if PTT is pressed model->muted = !model->muted; - model->callback_trigger_mute ? model->callback_trigger_mute(hid_ptt):0; + model->callback_trigger_mute ? model->callback_trigger_mute(hid_ptt) : 0; } else if(event->key == InputKeyRight) { - model->callback_trigger_camera ? model->callback_trigger_camera(hid_ptt):0; + model->callback_trigger_camera ? model->callback_trigger_camera(hid_ptt) : 0; } else if(event->key == InputKeyLeft) { - model->callback_trigger_hand ? model->callback_trigger_hand(hid_ptt):0; + model->callback_trigger_hand ? model->callback_trigger_hand(hid_ptt) : 0; } } else if(event->type == InputTypeLong && event->key == InputKeyRight) { model->muted = !model->muted; @@ -699,10 +764,11 @@ static void hid_ptt_process(HidPushToTalk* hid_ptt, InputEvent* event) { } else if(event->type == InputTypeLong && event->key == InputKeyLeft) { notification_message(hid_ptt->hid->notifications, &sequence_single_vibro); model->left_pressed = false; - view_dispatcher_switch_to_view(hid_ptt->hid->view_dispatcher, HidViewPushToTalkHelp); + view_dispatcher_switch_to_view( + hid_ptt->hid->view_dispatcher, HidViewPushToTalkHelp); } //LED - if (!model->muted || (model->ptt_pressed)) { + if(!model->muted || (model->ptt_pressed)) { notification_message(hid_ptt->hid->notifications, &sequence_set_red_255); } else { notification_message(hid_ptt->hid->notifications, &sequence_reset_red); @@ -747,45 +813,199 @@ HidPushToTalk* hid_ptt_alloc(Hid* hid) { view_set_orientation(hid_ptt->view, ViewOrientationVerticalFlip); with_view_model( - hid_ptt->view, HidPushToTalkModel * model, { + hid_ptt->view, + HidPushToTalkModel * model, + { model->transport = hid->transport; model->muted = true; // assume we're muted model->os = furi_string_alloc(); model->app = furi_string_alloc(); - }, true); + }, + true); FURI_LOG_I(TAG, "Calling adding list"); ptt_menu_add_list(hid->hid_ptt_menu, "macOS", HidPushToTalkMacOS); ptt_menu_add_list(hid->hid_ptt_menu, "Win/Linux", HidPushToTalkLinux); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "Google Meet", HidPushToTalkAppIndexGoogleMeet, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "Google Meet", HidPushToTalkAppIndexGoogleMeet, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "Google Hangouts", HidPushToTalkAppIndexGoogleHangouts, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "Google Hangouts", HidPushToTalkAppIndexGoogleHangouts, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "Discord", HidPushToTalkAppIndexDiscord, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "Discord", HidPushToTalkAppIndexDiscord, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "FaceTime", HidPushToTalkAppIndexFaceTime, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "Jamulus", HidPushToTalkAppIndexJamulus, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "Jamulus", HidPushToTalkAppIndexJamulus, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "Signal", HidPushToTalkAppIndexSignal, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "Signal", HidPushToTalkAppIndexSignal, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "Skype", HidPushToTalkAppIndexSkype, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "Skype", HidPushToTalkAppIndexSkype, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "Slack Call", HidPushToTalkAppIndexSlackCall, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "Slack Call", HidPushToTalkAppIndexSlackCall, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "Slack Hubble", HidPushToTalkAppIndexSlackHubble, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "Slack Hubble", HidPushToTalkAppIndexSlackHubble, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "TeamSpeak", HidPushToTalkAppIndexTeamSpeak, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "TeamSpeak", HidPushToTalkAppIndexTeamSpeak, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "Teams", HidPushToTalkAppIndexTeams, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "Teams", HidPushToTalkAppIndexTeams, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "Zoom", HidPushToTalkAppIndexZoom, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "Zoom", HidPushToTalkAppIndexZoom, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkMacOS, "Webex", HidPushToTalkAppIndexWebex, hid_ptt_menu_callback, hid_ptt); - ptt_menu_add_item_to_list(hid->hid_ptt_menu, HidPushToTalkLinux, "Webex", HidPushToTalkAppIndexWebex, hid_ptt_menu_callback, hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Google Meet", + HidPushToTalkAppIndexGoogleMeet, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Google Meet", + HidPushToTalkAppIndexGoogleMeet, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Google Hangouts", + HidPushToTalkAppIndexGoogleHangouts, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Google Hangouts", + HidPushToTalkAppIndexGoogleHangouts, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Discord", + HidPushToTalkAppIndexDiscord, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Discord", + HidPushToTalkAppIndexDiscord, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "FaceTime", + HidPushToTalkAppIndexFaceTime, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Jamulus", + HidPushToTalkAppIndexJamulus, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Jamulus", + HidPushToTalkAppIndexJamulus, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Signal", + HidPushToTalkAppIndexSignal, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Signal", + HidPushToTalkAppIndexSignal, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Skype", + HidPushToTalkAppIndexSkype, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Skype", + HidPushToTalkAppIndexSkype, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Slack Call", + HidPushToTalkAppIndexSlackCall, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Slack Call", + HidPushToTalkAppIndexSlackCall, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Slack Hubble", + HidPushToTalkAppIndexSlackHubble, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Slack Hubble", + HidPushToTalkAppIndexSlackHubble, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "TeamSpeak", + HidPushToTalkAppIndexTeamSpeak, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "TeamSpeak", + HidPushToTalkAppIndexTeamSpeak, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Teams", + HidPushToTalkAppIndexTeams, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Teams", + HidPushToTalkAppIndexTeams, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Zoom", + HidPushToTalkAppIndexZoom, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Zoom", + HidPushToTalkAppIndexZoom, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Webex", + HidPushToTalkAppIndexWebex, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Webex", + HidPushToTalkAppIndexWebex, + hid_ptt_menu_callback, + hid_ptt); hid_ptt->help = widget_alloc(); view_set_previous_callback(widget_get_view(hid_ptt->help), hid_ptt_view); - view_dispatcher_add_view(hid->view_dispatcher, HidViewPushToTalkHelp, widget_get_view(hid_ptt->help)); + view_dispatcher_add_view( + hid->view_dispatcher, HidViewPushToTalkHelp, widget_get_view(hid_ptt->help)); return hid_ptt; } @@ -793,10 +1013,13 @@ void hid_ptt_free(HidPushToTalk* hid_ptt) { furi_assert(hid_ptt); notification_message(hid_ptt->hid->notifications, &sequence_reset_red); with_view_model( - hid_ptt->view, HidPushToTalkModel * model, { - furi_string_free(model->os); - furi_string_free(model->app); - }, true); + hid_ptt->view, + HidPushToTalkModel * model, + { + furi_string_free(model->os); + furi_string_free(model->app); + }, + true); view_dispatcher_remove_view(hid_ptt->hid->view_dispatcher, HidViewPushToTalkHelp); widget_free(hid_ptt->help); view_free(hid_ptt->view); @@ -806,10 +1029,13 @@ void hid_ptt_free(HidPushToTalk* hid_ptt) { void hid_ptt_set_connected_status(HidPushToTalk* hid_ptt, bool connected) { furi_assert(hid_ptt); with_view_model( - hid_ptt->view, HidPushToTalkModel * model, { - if (!connected && model->connected) { + hid_ptt->view, + HidPushToTalkModel * model, + { + if(!connected && model->connected) { notification_message(hid_ptt->hid->notifications, &sequence_single_vibro); } model->connected = connected; - }, true); + }, + true); } diff --git a/applications/system/hid_app/views/hid_ptt.h b/applications/system/hid_app/views/hid_ptt.h index 44883edd2..219e1c537 100644 --- a/applications/system/hid_app/views/hid_ptt.h +++ b/applications/system/hid_app/views/hid_ptt.h @@ -15,5 +15,5 @@ void hid_ptt_set_connected_status(HidPushToTalk* hid_ptt, bool connected); enum HidPushToTalkOSes { HidPushToTalkMacOS, - HidPushToTalkLinux, + HidPushToTalkLinux, }; diff --git a/applications/system/hid_app/views/hid_ptt_menu.c b/applications/system/hid_app/views/hid_ptt_menu.c index d84a394f4..074c85ba7 100644 --- a/applications/system/hid_app/views/hid_ptt_menu.c +++ b/applications/system/hid_app/views/hid_ptt_menu.c @@ -58,11 +58,12 @@ typedef struct { size_t list_position; size_t position; size_t window_position; - PushToTalkMenuList *lists; + PushToTalkMenuList* lists; int lists_count; } HidPushToTalkMenuModel; -static void hid_ptt_menu_draw_list(Canvas* canvas, void* context, const PushToTalkMenuItemArray_t items) { +static void + hid_ptt_menu_draw_list(Canvas* canvas, void* context, const PushToTalkMenuItemArray_t items) { furi_assert(context); HidPushToTalkMenuModel* model = context; const uint8_t item_height = 16; @@ -71,7 +72,8 @@ static void hid_ptt_menu_draw_list(Canvas* canvas, void* context, const PushToTa canvas_set_font(canvas, FontSecondary); size_t position = 0; PushToTalkMenuItemArray_it_t it; - for(PushToTalkMenuItemArray_it(it, items); !PushToTalkMenuItemArray_end_p(it); PushToTalkMenuItemArray_next(it)) { + for(PushToTalkMenuItemArray_it(it, items); !PushToTalkMenuItemArray_end_p(it); + PushToTalkMenuItemArray_next(it)) { const size_t item_position = position - model->window_position; const size_t items_on_screen = 3; uint8_t y_offset = 16; @@ -105,15 +107,14 @@ static void hid_ptt_menu_draw_list(Canvas* canvas, void* context, const PushToTa position++; } - elements_scrollbar_pos(canvas, 128 , 17, 46, model->position, PushToTalkMenuItemArray_size(items)); + elements_scrollbar_pos( + canvas, 128, 17, 46, model->position, PushToTalkMenuItemArray_size(items)); } -PushToTalkMenuList * hid_ptt_menu_get_list_at_index( - void* context, - uint32_t index) { +PushToTalkMenuList* hid_ptt_menu_get_list_at_index(void* context, uint32_t index) { furi_assert(context); HidPushToTalkMenuModel* model = context; - for (int i = 0; i < model->lists_count; i++) { + for(int i = 0; i < model->lists_count; i++) { PushToTalkMenuList* list = &model->lists[i]; if(index == list->index) { return list; @@ -125,7 +126,7 @@ PushToTalkMenuList * hid_ptt_menu_get_list_at_index( static void hid_ptt_menu_draw_callback(Canvas* canvas, void* context) { furi_assert(context); HidPushToTalkMenuModel* model = context; - if (model->lists_count == 0){ + if(model->lists_count == 0) { return; } uint8_t item_width = canvas_width(canvas) - 5; @@ -139,32 +140,28 @@ static void hid_ptt_menu_draw_callback(Canvas* canvas, void* context) { FuriString* disp_str; disp_str = furi_string_alloc_set(list->label); elements_string_fit_width(canvas, disp_str, item_width - (6 * 2)); - uint8_t x_pos = (canvas_width(canvas) - canvas_string_width(canvas,furi_string_get_cstr(disp_str))) / 2; - canvas_draw_str(canvas,x_pos,11,furi_string_get_cstr(disp_str)); + uint8_t x_pos = + (canvas_width(canvas) - canvas_string_width(canvas, furi_string_get_cstr(disp_str))) / 2; + canvas_draw_str(canvas, x_pos, 11, furi_string_get_cstr(disp_str)); furi_string_free(disp_str); canvas_set_font(canvas, FontSecondary); - hid_ptt_menu_draw_list( - canvas, - context, - list->items - ); + hid_ptt_menu_draw_list(canvas, context, list->items); } -void ptt_menu_add_list( - HidPushToTalkMenu* hid_ptt_menu, - const char* label, - uint32_t index) { +void ptt_menu_add_list(HidPushToTalkMenu* hid_ptt_menu, const char* label, uint32_t index) { furi_assert(label); furi_assert(hid_ptt_menu); with_view_model( - hid_ptt_menu->view, HidPushToTalkMenuModel * model, + hid_ptt_menu->view, + HidPushToTalkMenuModel * model, { - if (model->lists_count == 0) { - model->lists = (PushToTalkMenuList *)malloc(sizeof(PushToTalkMenuList)); + if(model->lists_count == 0) { + model->lists = (PushToTalkMenuList*)malloc(sizeof(PushToTalkMenuList)); } else { - model->lists = (PushToTalkMenuList *)realloc(model->lists, (model->lists_count + 1) * sizeof(PushToTalkMenuList)); + model->lists = (PushToTalkMenuList*)realloc( + model->lists, (model->lists_count + 1) * sizeof(PushToTalkMenuList)); } - if (model->lists == NULL) { + if(model->lists == NULL) { FURI_LOG_E(TAG, "Memory reallocation failed (%i)", model->lists_count); return; } @@ -177,7 +174,6 @@ void ptt_menu_add_list( true); } - void ptt_menu_add_item_to_list( HidPushToTalkMenu* hid_ptt_menu, uint32_t list_index, @@ -190,10 +186,11 @@ void ptt_menu_add_item_to_list( furi_assert(hid_ptt_menu); UNUSED(list_index); with_view_model( - hid_ptt_menu->view, HidPushToTalkMenuModel * model, + hid_ptt_menu->view, + HidPushToTalkMenuModel * model, { PushToTalkMenuList* list = hid_ptt_menu_get_list_at_index(model, list_index); - if (list == NULL){ + if(list == NULL) { FURI_LOG_E(TAG, "Adding item %s to unknown index %li", label, list_index); return; } @@ -206,16 +203,17 @@ void ptt_menu_add_item_to_list( true); } -void ptt_menu_shift_list(HidPushToTalkMenu* hid_ptt_menu, int shift){ +void ptt_menu_shift_list(HidPushToTalkMenu* hid_ptt_menu, int shift) { size_t new_position = 0; uint32_t index = 0; with_view_model( - hid_ptt_menu->view, HidPushToTalkMenuModel * model, + hid_ptt_menu->view, + HidPushToTalkMenuModel * model, { - int new_list_position = (short) model->list_position + shift; - if (new_list_position >= model->lists_count) { + int new_list_position = (short)model->list_position + shift; + if(new_list_position >= model->lists_count) { new_list_position = 0; - } else if (new_list_position < 0) { + } else if(new_list_position < 0) { new_list_position = model->lists_count - 1; } PushToTalkMenuList* list = &model->lists[model->list_position]; @@ -225,8 +223,9 @@ void ptt_menu_shift_list(HidPushToTalkMenu* hid_ptt_menu, int shift){ size_t position = 0; // Find item index from current list PushToTalkMenuItemArray_it_t it; - for(PushToTalkMenuItemArray_it(it, list->items); !PushToTalkMenuItemArray_end_p(it); PushToTalkMenuItemArray_next(it)) { - if (position == model->position){ + for(PushToTalkMenuItemArray_it(it, list->items); !PushToTalkMenuItemArray_end_p(it); + PushToTalkMenuItemArray_next(it)) { + if(position == model->position) { index = PushToTalkMenuItemArray_cref(it)->index; break; } @@ -235,8 +234,10 @@ void ptt_menu_shift_list(HidPushToTalkMenu* hid_ptt_menu, int shift){ // Try to find item with the same index in a new list position = 0; bool item_exists_in_new_list = false; - for(PushToTalkMenuItemArray_it(it, new_list->items); !PushToTalkMenuItemArray_end_p(it); PushToTalkMenuItemArray_next(it)) { - if (PushToTalkMenuItemArray_cref(it)->index == index) { + for(PushToTalkMenuItemArray_it(it, new_list->items); + !PushToTalkMenuItemArray_end_p(it); + PushToTalkMenuItemArray_next(it)) { + if(PushToTalkMenuItemArray_cref(it)->index == index) { item_exists_in_new_list = true; new_position = position; break; @@ -246,20 +247,20 @@ void ptt_menu_shift_list(HidPushToTalkMenu* hid_ptt_menu, int shift){ // This list item is not presented in a new list, let's try to keep position as is. // If it's out of range for the new list set it to the end - if (!item_exists_in_new_list) { + if(!item_exists_in_new_list) { new_position = items_size - 1 < model->position ? items_size - 1 : model->position; } // Tune window position. As we have 3 items on screen, keep focus centered const size_t items_on_screen = 3; - if (new_position >= items_size - 1) { - if (items_size < items_on_screen + 1) { + if(new_position >= items_size - 1) { + if(items_size < items_on_screen + 1) { new_window_position = 0; } else { new_window_position = items_size - items_on_screen; } - } else if (new_position < items_on_screen - 1) { + } else if(new_position < items_on_screen - 1) { new_window_position = 0; } else { new_window_position = new_position - 1; @@ -273,7 +274,8 @@ void ptt_menu_shift_list(HidPushToTalkMenu* hid_ptt_menu, int shift){ void ptt_menu_process_up(HidPushToTalkMenu* hid_ptt_menu) { with_view_model( - hid_ptt_menu->view, HidPushToTalkMenuModel * model, + hid_ptt_menu->view, + HidPushToTalkMenuModel * model, { PushToTalkMenuList* list = &model->lists[model->list_position]; const size_t items_on_screen = 3; @@ -296,7 +298,8 @@ void ptt_menu_process_up(HidPushToTalkMenu* hid_ptt_menu) { void ptt_menu_process_down(HidPushToTalkMenu* hid_ptt_menu) { with_view_model( - hid_ptt_menu->view, HidPushToTalkMenuModel * model, + hid_ptt_menu->view, + HidPushToTalkMenuModel * model, { PushToTalkMenuList* list = &model->lists[model->list_position]; const size_t items_on_screen = 3; @@ -320,7 +323,8 @@ void ptt_menu_process_ok(HidPushToTalkMenu* hid_ptt_menu) { PushToTalkMenuList* list = NULL; PushToTalkMenuItem* item = NULL; with_view_model( - hid_ptt_menu->view, HidPushToTalkMenuModel * model, + hid_ptt_menu->view, + HidPushToTalkMenuModel * model, { list = &model->lists[model->list_position]; const size_t items_size = PushToTalkMenuItemArray_size(list->items); @@ -390,24 +394,30 @@ HidPushToTalkMenu* hid_ptt_menu_alloc(Hid* hid) { view_set_input_callback(hid_ptt_menu->view, hid_ptt_menu_input_callback); with_view_model( - hid_ptt_menu->view, HidPushToTalkMenuModel * model, { + hid_ptt_menu->view, + HidPushToTalkMenuModel * model, + { model->lists_count = 0; model->position = 0; model->window_position = 0; - }, true); + }, + true); return hid_ptt_menu; } void hid_ptt_menu_free(HidPushToTalkMenu* hid_ptt_menu) { furi_assert(hid_ptt_menu); with_view_model( - hid_ptt_menu->view, HidPushToTalkMenuModel * model, { - for (int i = 0; i < model->lists_count; i++) { + hid_ptt_menu->view, + HidPushToTalkMenuModel * model, + { + for(int i = 0; i < model->lists_count; i++) { PushToTalkMenuItemArray_clear(model->lists[i].items); furi_string_free(model->lists[i].label); } free(model->lists); - }, true); + }, + true); view_free(hid_ptt_menu->view); free(hid_ptt_menu); } diff --git a/applications/system/hid_app/views/hid_ptt_menu.h b/applications/system/hid_app/views/hid_ptt_menu.h index b273ab74d..c6dc53d55 100644 --- a/applications/system/hid_app/views/hid_ptt_menu.h +++ b/applications/system/hid_app/views/hid_ptt_menu.h @@ -5,7 +5,12 @@ typedef struct Hid Hid; typedef struct HidPushToTalkMenu HidPushToTalkMenu; -typedef void (*PushToTalkMenuItemCallback)(void* context, uint32_t listIndex, FuriString* listLabel, uint32_t itemIndex, FuriString* itemLabel ); +typedef void (*PushToTalkMenuItemCallback)( + void* context, + uint32_t listIndex, + FuriString* listLabel, + uint32_t itemIndex, + FuriString* itemLabel); HidPushToTalkMenu* hid_ptt_menu_alloc(Hid* bt_hid); @@ -21,7 +26,4 @@ void ptt_menu_add_item_to_list( PushToTalkMenuItemCallback callback, void* callback_context); -void ptt_menu_add_list( - HidPushToTalkMenu* hid_ptt_menu, - const char* label, - uint32_t index); \ No newline at end of file +void ptt_menu_add_list(HidPushToTalkMenu* hid_ptt_menu, const char* label, uint32_t index); \ No newline at end of file