From 5bd35f435be38b73b3713ae10ccde08a8fc9081d Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Mon, 10 Feb 2025 18:35:39 +0900 Subject: [PATCH 01/14] [FL-3951] Add the Showtime animation (#4100) * Add the Showtime animation * Format images --- .../external/L1_Showtime_128x64/frame_0.png | Bin 0 -> 542 bytes .../external/L1_Showtime_128x64/frame_1.png | Bin 0 -> 696 bytes .../external/L1_Showtime_128x64/frame_10.png | Bin 0 -> 779 bytes .../external/L1_Showtime_128x64/frame_11.png | Bin 0 -> 753 bytes .../external/L1_Showtime_128x64/frame_12.png | Bin 0 -> 749 bytes .../external/L1_Showtime_128x64/frame_13.png | Bin 0 -> 646 bytes .../external/L1_Showtime_128x64/frame_14.png | Bin 0 -> 708 bytes .../external/L1_Showtime_128x64/frame_15.png | Bin 0 -> 707 bytes .../external/L1_Showtime_128x64/frame_16.png | Bin 0 -> 515 bytes .../external/L1_Showtime_128x64/frame_17.png | Bin 0 -> 525 bytes .../external/L1_Showtime_128x64/frame_18.png | Bin 0 -> 581 bytes .../external/L1_Showtime_128x64/frame_19.png | Bin 0 -> 553 bytes .../external/L1_Showtime_128x64/frame_2.png | Bin 0 -> 744 bytes .../external/L1_Showtime_128x64/frame_20.png | Bin 0 -> 626 bytes .../external/L1_Showtime_128x64/frame_21.png | Bin 0 -> 676 bytes .../external/L1_Showtime_128x64/frame_22.png | Bin 0 -> 676 bytes .../external/L1_Showtime_128x64/frame_23.png | Bin 0 -> 597 bytes .../external/L1_Showtime_128x64/frame_24.png | Bin 0 -> 550 bytes .../external/L1_Showtime_128x64/frame_25.png | Bin 0 -> 525 bytes .../external/L1_Showtime_128x64/frame_26.png | Bin 0 -> 639 bytes .../external/L1_Showtime_128x64/frame_27.png | Bin 0 -> 606 bytes .../external/L1_Showtime_128x64/frame_28.png | Bin 0 -> 716 bytes .../external/L1_Showtime_128x64/frame_29.png | Bin 0 -> 614 bytes .../external/L1_Showtime_128x64/frame_3.png | Bin 0 -> 696 bytes .../external/L1_Showtime_128x64/frame_30.png | Bin 0 -> 750 bytes .../external/L1_Showtime_128x64/frame_31.png | Bin 0 -> 782 bytes .../external/L1_Showtime_128x64/frame_32.png | Bin 0 -> 474 bytes .../external/L1_Showtime_128x64/frame_33.png | Bin 0 -> 523 bytes .../external/L1_Showtime_128x64/frame_34.png | Bin 0 -> 577 bytes .../external/L1_Showtime_128x64/frame_35.png | Bin 0 -> 579 bytes .../external/L1_Showtime_128x64/frame_36.png | Bin 0 -> 321 bytes .../external/L1_Showtime_128x64/frame_37.png | Bin 0 -> 570 bytes .../external/L1_Showtime_128x64/frame_38.png | Bin 0 -> 775 bytes .../external/L1_Showtime_128x64/frame_39.png | Bin 0 -> 795 bytes .../external/L1_Showtime_128x64/frame_4.png | Bin 0 -> 713 bytes .../external/L1_Showtime_128x64/frame_40.png | Bin 0 -> 703 bytes .../external/L1_Showtime_128x64/frame_41.png | Bin 0 -> 681 bytes .../external/L1_Showtime_128x64/frame_42.png | Bin 0 -> 665 bytes .../external/L1_Showtime_128x64/frame_43.png | Bin 0 -> 794 bytes .../external/L1_Showtime_128x64/frame_44.png | Bin 0 -> 888 bytes .../external/L1_Showtime_128x64/frame_45.png | Bin 0 -> 914 bytes .../external/L1_Showtime_128x64/frame_46.png | Bin 0 -> 913 bytes .../external/L1_Showtime_128x64/frame_47.png | Bin 0 -> 929 bytes .../external/L1_Showtime_128x64/frame_48.png | Bin 0 -> 925 bytes .../external/L1_Showtime_128x64/frame_49.png | Bin 0 -> 925 bytes .../external/L1_Showtime_128x64/frame_5.png | Bin 0 -> 735 bytes .../external/L1_Showtime_128x64/frame_6.png | Bin 0 -> 762 bytes .../external/L1_Showtime_128x64/frame_7.png | Bin 0 -> 764 bytes .../external/L1_Showtime_128x64/frame_8.png | Bin 0 -> 741 bytes .../external/L1_Showtime_128x64/frame_9.png | Bin 0 -> 721 bytes .../external/L1_Showtime_128x64/meta.txt | 23 ++++++++++++++++++ assets/dolphin/external/manifest.txt | 11 +++++++-- 52 files changed, 32 insertions(+), 2 deletions(-) create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_0.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_1.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_10.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_11.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_12.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_13.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_14.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_15.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_16.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_17.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_18.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_19.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_2.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_20.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_21.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_22.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_23.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_24.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_25.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_26.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_27.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_28.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_29.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_3.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_30.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_31.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_32.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_33.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_34.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_35.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_36.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_37.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_38.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_39.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_4.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_40.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_41.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_42.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_43.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_44.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_45.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_46.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_47.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_48.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_49.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_5.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_6.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_7.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_8.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/frame_9.png create mode 100755 assets/dolphin/external/L1_Showtime_128x64/meta.txt diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_0.png b/assets/dolphin/external/L1_Showtime_128x64/frame_0.png new file mode 100755 index 0000000000000000000000000000000000000000..7eed9a024d332e5e7ec021b2b3cd6f476975fb16 GIT binary patch literal 542 zcmV+(0^$9MP)oo$o%Efhiw;W8T4m9CRZ$kDScqeqUj5j+{f6lNhaLuWAR=@)&3hVyb+T)K2A(FeNJCEZPz zs^H+jaVqFxqMh1F$OS!&k+|Pm{dKx5hSG<2 zinLkR!1?Co0WbHx8;L8 z)G^@P-_R$Pie1}<^@;zQ?d+~Z&5i84)d=}k_xH7EXmd&Xexu~j=a~|<6kWr()WRF( gvin-}hxI?<3w|ZWq$Zfwg#Z8m07*qoM6N<$g0Rj9MgRZ+ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_1.png b/assets/dolphin/external/L1_Showtime_128x64/frame_1.png new file mode 100755 index 0000000000000000000000000000000000000000..827730087e4827b0164437625a8395f7a8a310f4 GIT binary patch literal 696 zcmV;p0!RIcP)`=p0c0>DKMXbmtF04TWF8lX`Gzz5c?0T?m> zCgXlHP;m+Xba2Cf3jIz=U_c6cIUEU`fEF5yy1c1vQAksH*w`jIpak zBbYix{cgsqR&$I0W9gah>3v3}MoUoSTzx+?O7t%xP33KMCo`jz-L!^2eNpe9&WxQD z4_(64uj=E|iIG9Y(ZThu-dAQ!MoO6py6Tk~6&jT$UV+zkpwd;=Ccu$bwqWum@XIMi zpSQp$DH%8nUg}S>rG;+DjI?k&E*SArZPFt2(niHH%`IH?0pL1V{4}o&o9%;u1wU<8 z@ag{mpEeOVdkN^$5aDtKyB-q#!_Xxs6~;!AU>&?9Wy^&H;8!w0wq%*@3;hEyTbjzf z6@XU2cNUDow$=vt(gF<0*KLQ(JNsBu0yN69yT)2Vd&r-%7(f8LnRxow0*t9U3vRt< z5i&~v7D2Z^v7pMongIKC{pc+V7`-rEhRt0)|9+dYU|!-LelR{OTTlQFUi~cJnijmA ecJXbzll}v1k#w&P1Wh6U0000FlED}_kVEmN0WXRBp)`bQf^pyVd<}4P0E`ov)1=DnDJmsYwl0p+g z$Ph{g4INt5q#iRA`V`!dAx3IK{y<-l;uK8LAk|51**v||L2_dEx1Epg9`3#87(V>v zuLg4fM5m8bEHk9uqZcW+#F)`Xf4avW^o^l|){FzGUE|59$Q01@0ocq3ZLvk-q+9@o z%OFFwy#~mEA7P&{IsHH5lWXkkGcJt*&1C={=HE=pp$w3k1>jg2Po@gQ=bOt^1RmzE z#%*!wT}Ykk8(SaPd){+sF3kbtv2{KQTes)4k=`|`sv+_*?0nz6;Q^6}e_D|5V7G@L zKP6=>1e#0BFJLp%HFuc+_e8dldlxu-gimi&d;{952fW`aO^_9bGy$)&B8`7D?8$=FgJEM2xGZba(0L7Vb}|GX z)!x?CS7e-hS&#<6_;F*5F~)LP0Qju^sz(nntE!tdU`5bD@Y2B0+ZwVUL>oZz^*!ju za7+C%Bq!&0ZZkO32bL9_$scl^#otv`RkwpPWG`eV&Q6@`ftNufuIv8nuk9X@!*q^1 z>%Wcn1bt9HPdh$R4Ho<0pK6y2aZDuKDs75CHXhc=Js@jbl z=@{b;BmqMSOp%IyoxNFC)ksxCeJZ+mt6pIPj0Z7yRQR(p)lE?w_RT+*Fz;vEW5 zg8SYPLt(b?AB&`tt>{|CVCMZJTd>W%;a002ov JPDHLkV1mV`Z4>|i literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_11.png b/assets/dolphin/external/L1_Showtime_128x64/frame_11.png new file mode 100755 index 0000000000000000000000000000000000000000..0535101be90b52ecc2b3a0ec5b02c5dfe0ff8c95 GIT binary patch literal 753 zcmV4`mx9M^9!}L;|fO3dVpVyB13#bJ&Td$!0q{uZP{uAD`Rz@OvJ_W^Z}VR@v2AU2oU-JtmK18>=7I?E&!cH zkdE2S1jw$tu!Yz^@DXw1H|kr6UweUY5`ek3Ao8dhVNQ`r)AiqGnLy$kx z(i;Qe#N;xp^f%13L^e2?Q)!?Rn3mfy5Z(`fJjO@-7|6IbP@E-)cs~K*WVq8`$pf)4 z0`-i$4LXa5!IESi_^YxCgARbm@4z<9vg-+ykktYX|C=maOP-LmWqYAXfG5D3yt)c3 zq2SRUW67TL0Qwrv#nABN>|W~4L3#j}WViz0uff&EEF6=0NJ9$L1sK5HUM>5i@JN9P z6tr57NHuFrkRz+ztU|oOQWv{1+s)>((yqSdYj)Q#-Ua?d)n9bDejHobH8x+mW|3k-QI<7wvZB z``ukE)Xeze`r~RUiw?e3Rn>;7#?D@;8RJC}V7Lutgp&UJ!1brY$Z27rmEvpI-^TUVJONzP*v5kswQK0dI27Owf+HF j`(#gwV+s(Zfj1ujtfoifv3sDi00000NkvXXu0mjfVGCrJ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_12.png b/assets/dolphin/external/L1_Showtime_128x64/frame_12.png new file mode 100755 index 0000000000000000000000000000000000000000..1284019a8a145db5eca8347029b35636d2c09125 GIT binary patch literal 749 zcmVUfot%rghw0K+)BnO2EBJ|Q7@sJ)Yc<@k4 z!KFP`>>j0uI-0OXg?6bRqFXX1LX;`)#73Rn&dlp!bd2x#QfnOel90edh zXTE_8!xeo~xn3S&8pD833y|pAnwXD(Isn{BKG-F)2Z#ay&WIIL>koU(6pH70TV=9e zCKThq&I4s)?3{0vY(!gl&F3-URPe~7O7(1EIhT;PpEJ!ozq zjTDHkbT^F;2{nmrsMHTT2sX@*q>}>CwLvkWDI`dNx@Tj90cRfoM6ld9L3 z!TjM$kN}LqYXB37OB1jG2bkRt%wSPg_X3QXosI)AkEObz zx*oQ}e^s-A!Bs8SQnSHnRJGVR05iyh_iMHQU#Y6T>H|w?Uft@LN7K<(kPDd=mxh#C zIXCV(C9qkN%hL}}Zb_VCW?{xH9WMvD?Rm+U?^@(zlk6TXH{OE#+kPUhOuZ;up8XlK zwrV|YzXeCva@G^`QGfPRZS~RZmHz!E5(g!rVHlA{_`2FCa8hTS{42J zWIk_5ISABT1~bMG!WfEScON_Foqr!~SzL}-0y@7tG5I7%7RNC&q! z??=Se0IF4!PYbwU|6S}@7(f-RZ-s%X-CF}ls#UKh`fS_IVX`3k*B>1wT-&w-Y#-9% z>`H+?+cqIFzll|x!iA79??4HkGHB_7yM}e`?K#p%UGAM>`~5}Z4VkZl;6+5S=;2gL z?QlNhf;EaYgi~{#)aHBnPQffCet2LFe)QZa06Rzk;D7MC0WdiL!`uu4z#6px!`cd= zj!j4umc6bh5@4wI`#y152P(zAf=04C_Sgn1d837ZelP9}l;FxkY43AXL$zZ3OEIA! z8S^{j)hfnXeeQqakD1N1wE2ctt;B|Tek)GwZg5JH@{*L6RF`Cc<}A+u=G8blA%e7I zeAEfRAy_Fe4`_t^OCSNJlPZvf$!+K%g;bPOQ(BTLH5r(sKwETOZ5ZS+d~)uY(|v;K z;Z$i!QeK8%@$DWA)p&3Tv+ak=V*nh?fCu~rI}4cnF5HBoA)CVNgf5C*w=ffQEw0>jF=+(} zF`x@e7hTMyrDUVVMcozN*nmlyLS7u1Op@pOT-?VbJ*&gHKfd$l>Mu3Hu<=>UW<}6sV zW%DH94^~dzpN(BI67U+I+MK0sP3)`MjQ4&Ow+wab*wUL?;=M2M{dkk5d1kzKkpOHd zYD@@ho*8hfXU^U)3vW7}`do45+$Iiy7W=$N*U~hUMCL{EM}ZGiB2gvuF0a-8nGlI~ zH7sgJ_9Wv(zpozitD#%+g&i+s1=w*U{~;!^i#;E|eG&_Cu&M0Q-h5e*ByESOl^fA) zS8DjXAD4ugnSB%-7NhL3u15Y>%q3}G`|1{@#v*XQ2b_)X1A3CSr1tA8?MU1MrXjq$ z1HeP~4Uj?W!wUdhb@w^|)TeF-K)>)vQYx*Bh9tdo4;G;hr~xo|Szbe%yE&7=dOfLs zYS`6bxm*Ca`FE3_0lLbEJ?T~Y`G$(NdrB~X%>i&QXUFCz93N;k=Idy_&Ng+Oo41U##~coJC@ zRInHkZI3$@3KhiYA)-{-32jN*1b1x0x^ZXc-@{~g;=8>c|M!32d+#$P07e4<{RBpQ z7^cKVXuj^R0JQD`QixF=g&8(rrlUybaz*S)`ZF#Z|LsKa(2TwH7FZnp`#Zwk$HfUr zaqOo4v9T1)m&J+FtiVZreKfBEEZl$k1OQdH0E~wzl>|egDz7Jv%YxkI$M8_L`e|UG>Ayd!I0G?2?6!_7$}cp~d-2@?g*GR@&ov3y z1NdYqg+e#&TU{bp+pDNM{*iExqHzAz_6XSSm7ksTuJlC8|3`Cuwd(&E=N3*)N;+*n z`$1|%&<465>6C(AU(9w%HTD0}zf^OusvXH*&TW6@BW~MobMOKaoU)gLPOdYc2P}0x zUe~1RioG${Es0=bWzRbHRiywcsVYgnqA+1f76^AYL=&(T+6x^3AvQuq0RFRV19pKV z6WlRG3a~|*Kn2SGjCjIBs!7_BFGT}eJF-ybDLnwgG*#PGi@jENuhp9K;TXz&1FQgnR54sghmO2Iu%*w#D_%Ew!i# pk9S&=l=^-))XPY8dw72tO{<;=XjW*scKWyOc4;k{tA%vE4f~bnYXJg`(fQwVA@j< z5MU^ua&o3HUy6(Aww_2MT;09VSrc0TTEENq_1WIc^oi&1QdiP<-!RvwPp7H4u|TtY zur+DXvH{39e4s6ym?9!gyqY-B)kQ>7#YZmbuv7r>2(gRG@#h7SWpe2h$nX9E0KBIQ zHWao2uyAwfkCacAceI;g{BePpdf7No`kD&q-**#``zB=;alno>%^^*szW~^%UeDlp zc6!xmVMRnlg6uIOSwD%U*SPtLWD#9_r(5QwA*m806Y!BKO@maa13%I}i#3wT$mZDU z4yevZ4$iHjKN=f)`CO!`I97hU{Ck}O_TtD z+XMhF%6{{XWl_W_EUut@*_002ovPDHLk FV1k{y@PGgS literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_17.png b/assets/dolphin/external/L1_Showtime_128x64/frame_17.png new file mode 100755 index 0000000000000000000000000000000000000000..4d0b7227ff8721640c6b1a2861e877c93c0c7eb0 GIT binary patch literal 525 zcmV+o0`mQdP)J!Rp^B4qlH+1BcP8D{Z*}kC`_4V*d>2k!Mkk;7-wLB+Z%6G#U@3gN2%Oir zlb=0+v-pn03g}^!TkwoArU%<*UH~SP-a8IS(+$(y)Vw@njJ+|~_45%=(j;c>lIs8r z@S&_D1(wS~S8lWRvn*_MUHg@Cw&$eTnKFlk-H!|Apc#~b09y7~N0C?t=vP@rb)fXo z)Lo^dp(LCZZoOv_9;tJSNx<;kg^E9GXc9&($8j_am4w=J92bTFTyY%4U~jVIgav^2 zgi1+ijB(!ZpgDwL324<5$by}BoSs0BA5KSKgc@met^;)y*EHjAv8ZVMH%3XpQ8!Ff7!#_hy{P><=kQ~`)GxP}k2)D(4_^?BeA{?Kwq3ja63d-i zTi-TJHWI)eZNDnawE{lvKe+eY0dbwr-Gi&-Dcg>vZ%$n_?oaKcvqXBhHSXnJD&Aw* z-10kax9MH!;Hes!7Ykkl)fx9Q9fVR%8n3E9Pwbu4kkUa8c-H`^xP1Nrxx4ZPM1)3a P00000NkvXXu0mjfqB!(u literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_18.png b/assets/dolphin/external/L1_Showtime_128x64/frame_18.png new file mode 100755 index 0000000000000000000000000000000000000000..d53d074e644a1e4812176442657fddb37fb7eb47 GIT binary patch literal 581 zcmV-L0=oT)P)`nhruzl;)**?|u%+i%A`-XZ&%_ckXw-3n!J)i7o$Me~H@T9Vdf-EirlvCw(6iJrC0Z;0d4&#W9z+jk0KTU_ZWQaqQyO%%DjTY6TUkERX*47?!)zEs5CBs(6XoF71T{({LAjJN zE*|F6sdd#<(r|e$36D8Lugr=u#sW;ep%i=?(fAlg?A;rHZa|x*ef$>)z^;14>(#A@ zJ9#eG+{3W>tdvOo^dc=gHJ>LXsV7O))y(vBE1i*=l4P&)(lK$AmSG>jJ~8nR+-$cB z3&t43jI^e#RS%WM0QM$|F~Ke9^uJ7^1IeX+sO^DUd`U}BmCg6H7{q_?9k`2u>_IS4plmQPbV5wjn3!9rEG_Mz^iMDruvcj8_!lTGHCSk3bgeA4 zq%htYO|&rHA_|AM>{#r+y~RqtYIia--^}~q)MIpd&Hqj-{byJA!b!jjKF243xy`J5 z0$7%o%1;ZxRk&LMBLe8cwX%aX#u(d$bEcR=^1^4z`AL$zd%?bnvBntV?T&u&O9_&6 z{A%#)rel=KfnU#&ulih}wsu0lL))%-97_B5OAi2Mqz^ZeTDKXg_ckiK0L;Sd&)Sw2 z=zF8aXwRb`=Z6fl8IgCW0Z{^Vn|hcpnma)mB*Phf+%xWKFw<+UEnH3|1^x9ZX%3LGRGBXOF~Ic-SbqpWIE-#Wh#7Z)Ny1wYRl$_AG!0D} z!@E2)ut4f0dpc^wOhk_z(D`#Q3NdY0PpzHaR_~qEDLuR-^ZWiJtdw2G)H!@})DQaZ zP%~-`l3aM@|H!T)F0J4_chT04HTb&qG1zvDD7SFOYdQa$5u%o rN%k0k$-FI^0PIPfdFiD#)RUyYy7Bcj>;v9u00000NkvXXu0mjf@T~=B literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_2.png b/assets/dolphin/external/L1_Showtime_128x64/frame_2.png new file mode 100755 index 0000000000000000000000000000000000000000..a52e051b9f04fcfc1940ae657851fc9f9996c096 GIT binary patch literal 744 zcmVP)e2c*0Z8Q~Nwtex2>|n0N>ZP+3?S{TB&nKR0Vb4^)SCanh#}%hDgg4D zvUXDR%%}k;tXoOiA>}&Y6i_SaCoro3Q}UE_0sqt(IRH-KeQ>uioJSV$9ee<+Dr&5E z(v1093d}M`)BcL=)71vR5iXF{d4KEa#iUdKkWYHrZ|`3oSVe%mO%-1G^#0{z$_PNY zl9Erj^<>))Anl~fRG&TBVHe2ZdafwN*Y>6vPy}o!*OCq&>;nep$+HZ&;kV8`6zp2H zH`M2vKkFlmtMpJhRJ7V(_tqQsx{nGRm){dMXd>gJ9--g$@<$zYJ=UOk6E>}nk7$+9 z7+9X%X=d;jy#X@d=AW^kh` z1Pt6gneuTO4S@5EVZxr&JX0;l4r6e2BK1y7ZDS1(oQI?aTx<*h*yU=h&v3zAZHC3> zzlL+SoKi4oG1vny_k!ji6D|xcW4s?8x>RtWJ^m68(aSbEm8!{YH5|)Cb3dDi>(xGvJfzb z2%?P^LiP&1z!euUx$I?sycRQ)giN#SyU(x>?>9q7l2mu_OLi5pdpB=woJ6OI%oBEV zk<7RtkbRa_^AyoIO@zi1DZn5JPW~lssZi{R1gYCeh>nR$V-?Cg(VMB6=p=X%rQttm zsZf6Gu?L+5FQV?1AJY3m^${ThgM{Fic(ZgfTb~6O5L_cAiFH3o%<^lTF)|4bDxCXw7B-RwRGim-3lV zQVL)uFRsI63SLCRX-P>aX&1mS1o#Qiv;hFW@FIp@4qQ6^sEtrk6-tszp917ZB3jH= zJdpw{Y~(E;WB{8R^`ul3aw6sn!ACS`dJ(e&x1#zwM}UqV^p5^8SCrV%3=ZWMpQ@Ih|#)*t<6woFfGpIdq&t^EH+CU;vlr?gAhv}rN=NA3 z3Y82f#9gx}#X_m$s)dU8hKhI6nLCe*`;m~dc{vZi=Wsq=3Q1B|un5hfiSyiln#sfb zG*K;xnYkHebHOxw+i7}=NKV)2fK|YY65z$qfVWQ)im)GnyZ0pNZlMwzR40iF-{?DD z{FQ-fq#a9 zt#3kvCzKxQKZ{a(cOV}y0YVv6h4`y9Dk0{s*R)b918f^2{yyEAPYmGTAVhG%q|_KF zNg}xY$F1Cw9Io%~M@Sxk?h7FMYUKk+jGI>O*^VH>juPu*? zRiZj4TJe08cLh`XF8<9{h`34wKPO6nMP_aVft{+GV?G=afj2$`9lxn6Oy+8UyYFE?T>0palOOZ7_c3gJXW$=TVB5Qpu$zPA zq5f-F>cRI=;Guv}22~;bELB9_#&t9fBj=Qu3(B7}LW(1xfNII&h@LiUXZQ15B z36e^sYmi@6kpW*?mXQet)$2))iIsX0)>*IqX> zvkb69z+<+Q=pPDv_pnQ+t{Eh5$F9qy`Qj^`;9vf4vVsfvYrtU9w(aA123CdyFk6t7 zeh3#~56pkP%US6qY{Di)X2;x1F-7_iAuPDg6CiRRH9I; z*(aL*=I`u(2V_A9n%q8J49nZ_0)8zE>f&NsyYJ*8e{qmi93P8-E&JZxIHsEhBUiawJ&=xrrg|)$e(o?Up@54R;Qs*+?JD6;NPL6<0000< KMNUMnLSTX!jXvH0 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_23.png b/assets/dolphin/external/L1_Showtime_128x64/frame_23.png new file mode 100755 index 0000000000000000000000000000000000000000..6507bdc6ba9c18d34baf7bf98cbe351f002fa0fd GIT binary patch literal 597 zcmV-b0;>IqP)4f26otQgXX4HpkwGjh)E!AG6cr)3M+dSTR=W@?G_b`jF;BtW0=xei86|iDk)(MB4`B(^8P*M6N0QnUS}!;(2R40q$7*=wOe85dx(UDr zU}_}kBj99xH!uN+Mv`hGNty$kIuDFOOT7UeC(AK$3T%Ap8MUdKfv@F23+SK#@U0`t zaPYGL-4QGS=!0gD!MB01Mh_1~3~;?si}Vf%xtKJP)Ll6I#ZLhCRSdvBe`5H3s{%$L zg?p{^bdlkh*_MqHfSuhMxPn0v?X_zE{V4E0769_^_i*yCH;dV2`~)I!NTS-b*F1ZB z*{#X^4&t9(^zq(u!>WT){0@?kEP)cgA6o$WfGY|(>VhdWdj&gx;f=s~y(xeYZprpbr5)xMk9g>mo0g!M>M@xrkP$Y`1 z1Y$R_{U3-GIPyQ`?0hz6i;h`U5L5kHoox?vJg>(%XTdTsA|^mW4|qA!Q){HE796N0yO zLl&`99Jtj9BoXu5?{%xs@5v(OaHsJFC6uY52YT3Q30cIRGTwXU0E$e&rqvp@Ze93%aQsh!Bn?;k6lGsRDaU2l-qP!3r)Q?<*zPIoI$9a0W{jQ~{~QYe3p^ z1c76vJfwjZ0(;x3G5UGK{Mt*>0?Yrlx&nBUqOBT?$H{6ApnfmukFCOedqS`jSCQAIS=Wt3ya)ccs$FoOvLXC oJQ8_yLe`K|z-{NG>%+ z4hguE?DJ1CYoB#f*z)+>oo{D%sU%5##Srpn%k*uxp00~SVl@yxxUJ_Y5#;Y~mmd(> zArWmL8h~GQIIN;_AZmcBrZ^;41MxTqRW*Z%nyA%m(`q~QXsen*L_bfpiknvbNC-Yx zHA%!S2oM(M;35{c4^^Y@HzW}Ygp1+>OIUhB&-A>}9FmB=qCa{Q0P;k@rqLRbh=qS# z7a=Ra8)A2$Zvv8t1-`s5LI+92zQV_)_pwOCNV`Z4Rzj4t2C#F+$eBcx)Pdte*!V~h zJh6}@@2Jz4;~Z)LOV#%xah5hJiDbv~01&$*V%bC|1GxN=Cfx@0fStZgzqKm^U{`0W z{g@K$Me%Z~9E1(k313 zfIUc?FqWm{o%95GOxL8bGgwbnvt%aSPl&a3a6ch(+rghnB7=pB$&mg(XTb}RDgd20 P00000NkvXXu0mjf-qPtm literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_26.png b/assets/dolphin/external/L1_Showtime_128x64/frame_26.png new file mode 100755 index 0000000000000000000000000000000000000000..93f02f48eda60abc18e49f3040e8314bbf0d9d54 GIT binary patch literal 639 zcmV-_0)YLAP)1wz*A_yIoQ6b_P=QOk4o~ zM=uvrq6m3azWS%JcNja;H4g-3tp{;sVYNUeBm$p4=vwO}n_jx;nt6A(7h9YQW z!X@>*c+z9s++n zckSleUSe1F-fpQ!s41z|mV?wnNGssuSVp|jFCEz)Vw2xEJV*(fXikZ>8R2*zaFh$W zL`xgrrMSCA*;uMe$Fivf^3bH&_9!`)j`wun?KL`x1V}Lqj4CZG&Wu^4xX573)=?ukY}6LKAT?eL0dRW#UXX6- z$WAe3^t>6gyk+Rk<(2^R4VYvC3V4%%=|7=5&v@wFMoT~*z^4L*%B9Jx%o%>M6%s)& zGrZ>Ip$ZhDH!Fa_z}UaY*ZvGJ0Cgxo&RM`9kTS(j^AfC9%egVgAo zL!dweK**7b0gjPgsR*W&(fv}#ITQgUM}Y!7>$WJOq+kFVN+`=&zNYQ4=1z{a7B>`S z=X`0*wA~DUva?RTf7U21By5N-h9;o=HoQna-!SS_~No1 zBvaB%!m^DVLp#zSs)67$Zpo@HX>)8~s2;%h%^(9zgz#y@&szFHPWsw+48LEY?L`A4 zg66Qbnc+R8R$h@89vHR}>QAGuI0GNl4b_v)z_wnVn|ljV0CW~#|JF0b(nwPgkc?dK s+EI077iVMv-G75Kpxbyt79)lw52^Q`kL}WJ5?ZZr;AHhndYf$IpCz?|u3H9)V(XsJ;7D$pgmT z-_eAbf9Wo-z;z(dk4rl6pRT@=d>Kk=cjJlSrG?ciZ2$-qqyEX?-s~J1Q?!R)PN!#{ zjEp68@OUohcr zn>T4~}NiP5?2CDxk9ZD%6^?~Y6Lx)lyY?I>vw8)?WbhMj5wcAx!a$qm; z_blLkW~IpY(Ts=ce=~ERNuCpy+bxqouo+wf!+Fa^n1#Rgo&u0qKCTf`8&0!=VFAnF z8KiJt&3Dwxpuw*Vxf^llloGyj$VD9uyD@tn0y*T@GaY8d5|vqe64nWeQ1pf}w1L6$ce_D8D>>zn{8A$lO=3e*O$G~vBE3zCh1Nk(QF_o0js@{nJ1DL$f-b!)D5AJHy7&hdNgNJA z5SLu(;-EBwmM+prHx*)SxwJj+UWX)2F7Ng|-}C#u--k9SX?;^wRb5rh)E@sj5cv!nEjPX8%{+iZe@pugZm%N~5Y+$@#{m#CHZ)p6Rkg01`fxF;hflSjqP75Z;V#9;4dR_%q@}J- zW+W+k0J|^91Fye}XFPyn6M)J%ZS6%Ob@kuUf1h6^Exbq&wEzGB07*qoM6N<$g20*% AcK`qY literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_3.png b/assets/dolphin/external/L1_Showtime_128x64/frame_3.png new file mode 100755 index 0000000000000000000000000000000000000000..e7bf65287dd05555c329f6c3639a316bdcda6d97 GIT binary patch literal 696 zcmV;p0!RIcP)~f&blyO4er%G`N5~6klg2{y zLl2{r)e({ZKtH#%yGUzSXUOqzB zGtABL_`QPJO{$l%hD9Bb6AY%%Y>J%*Rg2~N?hY79pTTTX?5#5z%J|(vha%WF)BD=lv4)))*q{(U}wx*?Py>9Cok1TVSv08Df+ojUwzt6hn+O zo9JfY^@z?8783jg zo|hco`(M?Q?CrEDgD9@Tt(;PHk{7*Miz=tWA@16I3fVpEB0k&!kJ0N+RFAWm$~;_J zKxEHuElk}1$hQh(ws6Bbx(_`02Px|h%VawKd|pgpVt7Y;A)lR~-31#>7sqGv&T4Nz z^)ZV(U2y%Uh~BL%s%syV#hu1#E>vc)8O et<|2s8vg;5T0WPiw&R!p0000P_^WAeeXw0DYs-~*4 z=1DvN?J5BOCcYtA2jEtZ*!mC0{}SO^o8+@M0IH1r{Y!`1p(F4lYXDg_cLZCLgSz|= zqT)$DJFb3%-zV1cZEbrnDwp2Vm2IjW{FCthk6<_154RfG$Is3-B0qij~m(A0#F zSPCa@7yTE@Q!nTRRMZEFuPx-nMiJS!6y~~hTmBW{`mPc6B#q8};#8{6=ifuAdhZqZU96*1cpjVMQ9`P~ncG_f+d?)54STeYX0NavAWFGMC?mm#4 z=TXZ=co;+gZNONBG=HHV2o`e!sB;(K=&{2fuhdTGLDUO$;b9B!0qD6%01hB_F`&!W za-z&;a~NRe83A}6-aHcmoZJ-Et%Lbuu;4`%t|RbOFhZ%PZa6_>URju=WgIZ&z^Ep( znmwlQ{$>3|Fd!d548TY}n2EvRfZv_y9vJ6jl?IDp8rnQuqv;u-5l zp#=(+ad8Z;^ppmEaN^>(pCtr?SJ*(@?ezf2VlbEq!pURt6YlZw_=}DNQyG`$EPr}n zr{W5jkDZL;Zq(~mqcXqo$6LrvPF#z+gr$H->0Ea5G-gFDvb4<_$DfMibN0*G*_K)S zn%9~5Fb-c`$EScPCF|zWmHSeCjp9xVnCYwX^rU0 zMld#E1#qeB7R9s2z@?_>-a-8*8rD!Q5nS0L$xbn%8tCZOV07*qoM6N<$f<-1~ng9R* literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_31.png b/assets/dolphin/external/L1_Showtime_128x64/frame_31.png new file mode 100755 index 0000000000000000000000000000000000000000..274a1607434e8871acf8242c4de39128ae34f102 GIT binary patch literal 782 zcmV+p1M&QcP)8gi(V>7j=mfedMkR6Lf!dCV&b8Q zc(Nc`^v^B9L zTS&+f0M@4f_;+!UtO3B4t)lfG#{U-K!aCXcrvRoH{rgHv{HGBlWD5Yr)TR-%YD1d) zM=_a@y?=_YS>G(oMU*0-*mmw5fGs9uiIN9Dm~wraMw6kRZcl@j=#RaVDIrVLxcBZU z3Y5F>wusWf&auyf(b@q`BU2J&i9SB*@1$U&o# z=q3bf81QSDSApCUys!a)0Tw#wy~K#4{Jta(e9qf=M6x z?e6H6k)kbd@a=h&t2ue~!mOmCer9FWJPapI%>fQ~KVgmTb|vFAAj3_L5$8SKQkqFp z{he=CZ49b!pdRoGH=f77qjxQ(oC0@{p7FL9H|^mpu)xE6sytJ4Bo%uk<@NTdQ6{9gY>Q``lLm!(B9^4UZvKM&-ae;rk1Pz9_BbQw5(nfyje z(#=Pt>xwlTSTW!MMQ14k^FNw*PXlZ9CIF*%aZ}5&w3JJkV)g2O07u4)RT4f26otR{X3Q)h$^;U2jlyhUVVA~A13T%g{0qBar(!FDvSYWMt(93wW2dEskVSt$ zKqG7+?ucMxkXa<`gqfXd@n(`Y!9v5{YWO(ky!+1Z0Qw>lQI6)!{5z;+jLw%)1Mvbf zlD{bAKQqz=?2(@>lmKKEXY%p-7@%_XnB7KqccT_*cyBS)FJrVgDSBl8+ z)iV|vz74)9xLtm$JrO^UARCto4buJcaDZDXoIsMFJ#J-(C2;q}Nnm~c3vdDTarG)N zrBPW>lETt_R)VFKKypw|v#Jj#MuUc^wrR1gtxb=sAFhESg)u0i@KiAcQ*~AHz7#T~ zT~;*{0VkStdPbpEpd-g4@QtFGiGVZg25$`Tb-(E6H`53PR@5=S&hgtPJraPNkylUeb5aPK< zF&h*_Rr8O%oaF;_2!NP5x)K*7yRi$v&<6UR|ID{7^NUI6t*uax8u2y$0OZP>S0P*Z Qp8x;=07*qoM6N<$f&(erhX4Qo literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_33.png b/assets/dolphin/external/L1_Showtime_128x64/frame_33.png new file mode 100755 index 0000000000000000000000000000000000000000..3cfbe5a982a6701e4a40313d4e4c6a678e0838b5 GIT binary patch literal 523 zcmV+m0`&cfP)F$SZSI-8X@2h5W58-nTWmq1d9~03l?_4 zTi6A$4F+WvQ5#7%h%hEQ_qCX>oxzX1<-cCI8DWenoWu6)en+^)WOY56|evnW1_l6L^l@;{=I1g&l`#~YJe)` z9E{3)ET9L8Qri` zX>J1w=nUU>ZT9t-o*m|SbX~aoGE@}(uni>UMG%aq?uoCWaWGf~zYGWn*diQLBz=OS zd$x#($kNo|UKXK&PuZg>%QX$)Cr%0aAS=7&|A~mm#~JtAL7_O=27}kO3$XtVv-=%X zzQ@Chv$J!W#8mw~zZ}{N6Guf&UhlER%+-lus`Kw`Y1E>&5|aTX$#vQ{=3B{Hj03o; z^XhQpnLCe)umF+4&i&>7mB&xDpVy&t_VW*Y?g?Zex8c#fyQqlR<2Mg(nro?1r;P)4e-9L0b0zr`FOmJ>VZ3`i|*(;;@W!GPE$EM!2$ zU4Q}DR5>Z_ zNd_Om4RFt)I{>7fq)?YaRVeA*0vPiMNSA_Tk~CU!dw!&K z*@5P{ud(q`TW}i^Nm5>q%;Z`HKoNLH*|H74@V5pK_Mmegn5e6XPjVE1dsokOZ^z#i5hPvY`h47Srm za2pBO1b_nI;ss#0nwTyI>`UAL09#8IAovH^(l1uy2mTNz(b#a1DFcQ&A}$oM7cSSbuR1y)F5zyP?c0VHin8qc(-2NX5I ziOD=rWY-!KfYLeVobw=kk)+hp5z?~af|B%FsOm^k6@ecz&bt730PbQ80)UGeEsSku z!n{q|F%32JW-TV$&N;W>0;C-dBx#~8Yt2f`(YISE9|Aa!I9k zeXD(F-o|Eokjl3T$s|6U}J~coA7~_`!x*q$x$rG@PzX9li08|Z7DgLwuD2{y&6wr;HPFBJt@wB6- z=Xrg_z3Ay^IIMuY@$_lnJ|HQ1y6pMv<9RHt2e5~<+`DK>8^9j(i08S(&gi2B)Nw<=^!onN$3-|(DI`cK~&Tv?5P0sL;IbaP=k~Wg`AxY^Mtxth= TXkbF400000NkvXXu0mjfHou8K literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_37.png b/assets/dolphin/external/L1_Showtime_128x64/frame_37.png new file mode 100755 index 0000000000000000000000000000000000000000..0384fbdae685dac5f198fa3a53d059ee8f01943e GIT binary patch literal 570 zcmV-A0>%A_P)Gsn6vTh;-S+mxC3jUN2)dybQCW9ahXYez5aEuJ;{K((1Sas zLrLg>5-ev(ElKmyz7>uN<^YgBr#}V236i9$9O3}N02p*Y9(NKR;y})!t^DU?8fREj`-0R93(M<0M67u2*~`ze01jXH*1;EN&T9dd@V1w{uO zxT?fez_?q< zNXAu2vK5u&!eF|R7QobK{F&baAeDYbAebE3St`imM#H$Q!9krSmfzMmRg=4I{Zw^) zGqZ68@YS3oHaxEYHe*3R6Q_v#l5~A3NfSv8BZ20=MU7DRVbNo$A>azY&CJXONe-XQ z%-VA6O*Ow&ol4SQ^)x?}W+J?dKyi2^>61JZk-24aAjzpVBjZw%R8Cq^Rn6C`(+JEY z#m-!kX8sYN98g8_uAcz0xsU_*lQV#|DOY>n0fq@cy|&NQ-tX4{$r#|~)#JBC02p`% z(0{5o&-UZ}DZu*J*4M|;SI(_5=f5LKXA?;Z8)}~+#4KZgfA!cdAJJEN;{X5v07*qo IM6N<$f|n!x761SM literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_38.png b/assets/dolphin/external/L1_Showtime_128x64/frame_38.png new file mode 100755 index 0000000000000000000000000000000000000000..2632807f9d08b1feab9b2817721a9cfb2251b819 GIT binary patch literal 775 zcmV+i1Ni)jP)3+Gul?^S>L zPW6_mD&>rFMs2DQ8>*^eTkY#D((X0rvnhz|A}_G8b^)4nbK~3AQm&Jyy2tfWpU^1f z45PO8w|-sPur7lV=F`8fL7%%7M0VSCc)xoAnjAj#ecM_Jz>gk0dD5p+o{8)dLYZ68 z1U#{=9Y7dCA3$W+#6bHrG~o&|tJ8Kw+=p*}6)N%~fFsWBi@AsoW~az#3Kbpzo+Cg= zd=rsJBSP0juVgoNQ2s}hc#}W!5nP5J5GtO2V?GW~1Mps77(TJ%UD{&=z{QsZ_`a9} zU=?T_S!*M}*n@`p5G-OkdjRM?1n>gV$W?R$0r-V|r&+%zcoEN-q%g`|;pup`rg34s zwl1`}f0Mn!@V3Nka2U~Lj))vnZ*jfQ|9bxM?*s{J+X@!O5z|QRSv|O;s=3_{S0w=* zxC;QW3K8}rdQO`V8tAO1&&7bT`@uR5^yiv-17|c;LIYf$kI~L0f~`;C0mMtlR^)Xk~aXV z^Ddj>@c|KbGGCcg!?y__E4t)NuO>P!D zaVwTMednt;Y(bddOTkXgtjtT2x6VkE#MOG}^gte8{0~7`Ud)~mK=S|q002ovPDHLk FV1m^RbFKgY literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_39.png b/assets/dolphin/external/L1_Showtime_128x64/frame_39.png new file mode 100755 index 0000000000000000000000000000000000000000..f257489a12a2e6df4f2d12aeda9800ac9d79ac2f GIT binary patch literal 795 zcmV+$1LXXPP)P;L>}7+|MffAz2=9TF{ys^E1yaKn)Px-_rT;sKxkoqk^Yc1=B!k2_Yb+{AY+J=Y$x5 z2o3_eA`1XyPsmCZTA5f2FbXt1>hRkt0QcE|!f!ETRsh~+5wwL(al>9H&l1_ zVJ-~%I~wW%U1{m;=BgsjnA+^8L9aC!`1WA`c5d06+`1>LhOp#k#Q2kU*i?1?)QlKT Z-2c>fc#PygC%6Cr002ovPDHLkV1lRQehmNs literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_4.png b/assets/dolphin/external/L1_Showtime_128x64/frame_4.png new file mode 100755 index 0000000000000000000000000000000000000000..8a0c1734eedb7e15bc915316aa9562fcdde96109 GIT binary patch literal 713 zcmV;)0yh1LP)1wo-P_e9Xeb6nf|-6+En*oUsC5W(KOt=)5DX2^!F(n% z<5IH0NghrBEx@=8hCuMR0Aw*f;)g)ewSoKu-H3Mr2!?|-{(Ke)g?^|c-Br+%-wu|< zAAsk@1?X`AL~a7BFmtXaFoG=PaQJIda5;WS%9f^F)c{X`MfrRQ_=$o?Cd88V(*XJf zPK6M8axzV&`jH;M1?ejS_=|8Unt(3(06;US3($$%G&`1~8INW#1r@(sYbXP_k|GT( zQ5cot&kPM2Ahy)6A59^a>CQ%h9xT-}f~>0Q`~)zH#!Zc- z$I)=H5yV1dmFf*4J#wxxmZ$@pQMr@(c&xz~p!;HXs^0OZ5ZkU>KDaz08%=rJ;&@vP zOt##mhdZMb; v$B)n2i5YmhtA3M|eW10OE(IthfN%c*{1i`Qd%d5600000NkvXXu0mjfguX}c literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_40.png b/assets/dolphin/external/L1_Showtime_128x64/frame_40.png new file mode 100755 index 0000000000000000000000000000000000000000..cbcff2c8937fa4d41c17b3a70792f924d957c98f GIT binary patch literal 703 zcmV;w0zmzVP)1v7Ztf&nN`loA5J^_0t5T#wKxl63raKWtTv$vuMY^(uQs^cploAod?ka8^ zkU|*-bRptKa{XE8LauZng+hD#1G>wkb~-aA=e%9qGPsnoHx*bn3&u%_xu;27DX2xXiH0`khiq|hr3fHvT5A=nBJd4ypx7Vf(Jkn93{XIYM|!QU!kO5@;%{{!vEZr70p z-1>Z11})tisH@^g-DjND{i-6RCHPHwYeqL;0GmVaAD%8VMw-Y)d?iU5`;3ux0@XBH z01MG8VvdyeaM-tbBk9x|bC6(idijYj{+cU&DK**|PG-x-IxECieu~P+h3Yn@mEcO? zfU6bGO8NZxKn)rTqw+4$fLd8lvoIn>Qx)CBLOG(%5JAe6hyN z=FQvpfRC8($icp|NJS0WV5<&d2Nr7NU{_YjO=FTkC{i@kb8Xb0c)gtJxX;i;FC}ey zJ@-YYuMq<)h98S9&bBKFz@eK)IWW>NRHdzeLO=7Ft#QV@f}a^;ra9QdyiUJO&uqi7 lRj{$ECA~j(Qh+Bt_zya`Pt|GWY{9iXaGrzBV1Ym?n|ZlqUCcxVxl%Q>(w<`A}~!u)y$#`(;&s z-;;6>$#c2+?Ug@j>5Y;E;7vTK!fB|`UKW7-k9ipKXz4EjfExc*h0~B@?ZKXU0Y|ZM z!0JlZk3N&Q%+w7Abode%v<4T`6((OW1g~><; z^i!0#xSR;eX`-+;YA$ln>ly=$1ZmU4ub5ELajtX0#{|nRH?j1u8HCWo0KPr7J@rxiX%nPQqtrg z*li<-q&aR*EiOfvR1yf}=C~p@vb(wH?K%6+FU8!<4*8l7emw8}9FU&PGMB%v z5dbh>CnD}=^IlF`5MR98luym^^_n!f_jpQN{{_7EnBQnDZ4tccgZ^W&&bkj236 zPm)gO;mz`n&2>1uXkztY6acBD^gxl911*=>EztQUq58$iHUu+9n5##@C&j;B5dZ;9 z37=PNV{o=2Hli~S!gS=3W%_Ir{!yW+h>ySgUl9Bn)kfOz>{iV|M_a4vsu*dxgd2L% zkf*o`c9eD|bkj1h!1BNRK6UJ9q{!oTHL|J0oJQ z=b|gUNTMPm+Ov{vP&i4k72=LE^z?UUo`q+}o%3|@tgA1)`SAYo<@<@m&mDC4($J1i z_CE0X1OYl1iho_;JnJBg-RiE;^FQcZ@Ue4rn@R+PvDE?K`+|T4|5OcC$|d6^0b{=K z=hi#LAuo;O(&Y}fPsM5XLYya@5vDZhL`z;Yk)DJlhn0!~)3pL*-NtpfV!wuwh0 zl`Npj4G+^PySEWQ=USzqMDqUMZ6Gf8eD>HG%xufAy}DZ7v^lv|;>Y!C=PH-^x#;p} zNU@L|>D@#}mefv%G430yo%Iz1!9%0rDmR^+Z60Pt^2q5>o3z$kD#SOaM4lXt48C|| zadTJn!k#CddF`I)Qb-pPLldGywPG!ijjC&}uMzDWuYNF>+7_N?ZjtC+oz+5H@~@fl zhCPV(jc4`8r_)G%Evh4KjA!Mg>8fyhM{5?%-{@ynm_L^l5bw9z&1K=+sTi6c4OYt3 zl5os0c;mx`DGIe`$?9lMx1 zgrHRh?P|T35SFt8c_h7}-iw(}BZ#xFpBA+e;iomw%w{I?vH(x@bBPs#6IxCku7iE!uvSg0WxbIZsHFb;oj*2H~xB>z#M<8Cs1J$gU6OV9VqI z2+oe=U|@U}HYYddb5Mv97|?(^b literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_44.png b/assets/dolphin/external/L1_Showtime_128x64/frame_44.png new file mode 100755 index 0000000000000000000000000000000000000000..6d9362c51df3966a23f10ba58693f7626ad0bb7d GIT binary patch literal 888 zcmV-;1Bd*HP)u&;=vX{SmUJ>(f@XZ z2#U?2f{3IeB0>aF2!*JaNeM|#O&}!=NV<~}l2x&pO{$qqcjxb6y?%Ijp3|dDZQyL{ z$?XSsH;+#)kAeW{5??U`Wu`R(NWOX)0B*SmP~t&IUpdH8^bjD=1b^*&l$+uFAOcXa z*&Vn1a>;5W7=w3h|nxka~nh!Gc%{6cvdp34zjkx`&zE<4Q-8D05X z-h?OfJCpuRSP`OcWz}Vqv4#5EkVeRUsPZ9qm54~cop&20{Mwq9QhR?*h? z_-!fErNix;+No^mBjYNvQwY#t%cdQ#7fqS@sJv=GbD0b((4h^glw~65q3%zU(On z;O=79kES4#=^aR!t=SOK%pU~DS$Hvn$2{U$JPoc}Ed(ZD88vdDcI|pCvYJ%99pC-M z$T^eE+e+cXDi~i5FdwvwguR$|U09TlYWTVIdXQqr_uwJF28vqOjZe(MTA#P-OP2mMm@MRrs1Mp3 zkU8->g;FO-1b{MYPuN%M=G4UAnL`9P39uzS9Iqlk$9@ECT9O>sF>owGNMUvM)*WAB z%?R+}+8^oAgr$+f67<=KV-2R4SW5jYkHd@&7uO3tU8b$-s}-Of`3Zi^)qDPQWgej& zQr!h*Lh}VG2RKO8Bgv9kK>`#Wa8&o3mg+3xLs0`sWooZoJcwwxr}+=717ZR%KkaG& O0000Z}n6FyRCJuoX11BtRP^sD}UtR{$UG@GP{WEChg9b*n-yW)eLB zGxNryV;&Zbh5*FY%3ghg;u=X20LdFi-p8R<1#Vd$(obQd68~vn*(RYbkOQNe_cA7_NI(S zKfdx6Y~^`jQtW5Kc`13#f5TCc<9)&{?NC%^KjnnAu{$Xk=CHL%^Czh-FR*kU`mWKf zf6`w1jIF&CkBbv}9$(yI@x=tWUiFZ8;Y2)KoANMpIG|jE*@6)dr(Z2%=GzoZXDRn zl1Z~98@N$FS*_{0aoiJD??E9Vm3BBv3P{=zoCdKE-X}z6pae7+SW4?G-=-$tzn>$Iv4le zm!LQ910YQ%-qm(?m`VY_NbBvmeMNty%#HnIeCF(~;puCH0a}5)W1p^$sLFUmR`xdr z%R>zDE5@+D4>2cN=WvdLgCZtT#%q}vVG1%J%n@yUs2)QaApt_gBmM*@RTw}Bg4x@6 zC0$Fp0<2^Z#cAGjOF1_LI#NgyT1FcU1LQt8%4f_bf%X2*O5KN zMZi8fI-q_1F-8Gs1oF3SJsV~*R}LVZ?$!D36sJ)O<{D31fy#Pr~m)}07*qoM6N<$f>f%j+yDRo literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_46.png b/assets/dolphin/external/L1_Showtime_128x64/frame_46.png new file mode 100755 index 0000000000000000000000000000000000000000..4c799effbdbc1ad6bff86b20237957487332494b GIT binary patch literal 913 zcmV;C18)3@P)$G9LDkQ|CiXrF10}?#yRMV-E<(93fsuo*1lyzEA%kL4g?QjsDt4l=w<5Y-ZbhE zh4r8)6G{pbq(#t!W$h+?OX?aG+rp%l!P<9bYYQ9M+aQ% zyIuR4$bI^I>rhnyHlu8hh3pL{?Sutj1fDw#v6Yg80Gsw z5;Vi#OrZpDVT~7{qKG2^#OfP0auAQ04G5*)*m~JPWzHJ{5L>A_%`Mgwxp>J9o7X|o zg}qBp(UI!AhztX(`kc`W9tS?_m(#E(U7lnDmSNYL+%{Qfq~M>07|1;-U!v|mJQ-Sp z1V5FO=y%Q3`uhi(zFKr{>np5cw?=fEHMnQOGBzLhm8*C}yt>jK9?ZIz{?a@5q!$*} z<&(@1G1oN1-!tblb+yf&ul8rP*RfC^z^f~_ty=uJmeo$F{Af%f?ZG0o>&I`wi|X^6 zqsW|PYs3th^&VZmo7-h@9+_~Y<_R@G5l5-UI$5Xqnc|;ExVp0HL;b4N?liTC6 zSjS^@mTJb)&J{gC-cdSOnY@qEn-9j!j3l{U6duQIOfsE#f_8hm^$=o-Vfbef?ba4^%zYp+$u;@223?4B# zRaAhe-aaD=KU(V!0O6j=XM^47A6^Um1{8<}KDFWLMt;a7QN;QaHMr4$WG{Y(w?I6! z1rn(_ckxp(f@Mg7kUweYU#!Ow7ZM=Q$KVnttN;jTv|dU2hAo}23}OMUUCG%&99$3s zRFRvJDe=Gr&a7utn{KVz>K2SRkhpV)3-#_Ip+8_Q4iV#s(ysm%RfA(uz*Z5R57LA@ zi+mJF(yd#nH&EsO7fnjnyUsjA=q?aPtet?$%ptQWs5Jh&M07rQ<)274hhQK9(7*FK n1U3O6KU?^nr7uAo6gmC_0sn?dbhNl_00000NkvXXu0mjf&o#8% literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_47.png b/assets/dolphin/external/L1_Showtime_128x64/frame_47.png new file mode 100755 index 0000000000000000000000000000000000000000..017549d298e6b3a72760490b0901d6e61ca952f9 GIT binary patch literal 929 zcmV;S177@zP)tv*eFK2XvYk_EKq5&#Hk&+!(G;z=X%w9yq1tXpU>y%3+6Gc&t152 zL&a~O*7?u^$VSQkP~+@$v9tgT!S3f_-6aeJ$nFL65@c*w7X%pcfRo@8^Z`;lQ^TC!{{xw6`4&JCqW{wK#^_D=1)#s^e+ zw!;Oc-SSq7>8|zx?LRwxq(ctWZI2n7Kfm}rWSrP$heVzTQ?l;XFTg(HpN*o^A?AXf zY#Q(zR`X4l1jFpJ($t@8&bUlIJ!%m!;r{|XyRP|gFfIyQ&i}^jbG0O`{HW0|(OA9e z-rg5CLVad+PZI-aqb3}GDTkr6nPnc9*A3<02~Og`QdvxGNS*Bj<9MnCeWuN_^D+S8 zp6eeIA?KVw)vP5xiA?cxYio*pdr*g0k0t4=+h zi5*slr~Ld9+L1pE6@Ra6Qq3TX*KFqK7-{RD&^lM4!z00zviRoBHtlNdrCNiW-=dIj zO^5;AbNMg*8ITi&BvGZ9$?o%?_o<|`+MvgoGehvDc2gUn1x5> literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_48.png b/assets/dolphin/external/L1_Showtime_128x64/frame_48.png new file mode 100755 index 0000000000000000000000000000000000000000..28497ac23a33044b9ebde7d5b1300e139065752b GIT binary patch literal 925 zcmV;O17iG%P)woq;znCFStr5>jX0vYI|iD^P-CpXa^v#6tLCR_dDW0Vsu5{XWAwwsKzU$`heYi9J z?YzH4%sPdaPUv=Xa_dFotgeLGMTJDAZt01Zp5W|Uqyw=InA;{_bnp8m6}W-fAYb|V z$=->oeusU+A-qbZZUx(`%b(SH)L+rzK}qb0=BbVC`vabVCx(P6bt(Bf4pGg(I|qf( z#wnWcT(;n&&kn@^Sbl0#Zu4kG&2C3r8vy27GJL_v#j`=&AU94Q zh&5ukw%QcrYrw}&H9fvp1FO5Lix^~!Np9ja=wA=R2SDtNwj_?j8kfcv76EDMz)8Z7 z=ANJT0cro#cQ>Oy5V64kv3a|5I;7S+E@2HohB<(kt5_!=#RQNS3}H8Kg5+zK0omwr zhcK5SiYYk|%i!pUc^m;Z1428Tyh*!>Ncs^7wH&3^(D8&yVG+dWVFIso-iy#$0OBxX zEwhlgEDhOl4>;mm)^<%-J!?VzK7(8U&4tfF7z)MN& zMI#5jXhPTcQ3LUVgV;g>Loh&MQb_^$zVP{?sT%SA!p<~zhddCxt zX2-wCWRD6!Axvc`WX0?zH6;Lpu=fQh->e4#3at<})@Jqy!+cTD2Q@s$$kqaRHFbeC`(9OhZ&G z;Eui+Z-g+U!jgeKnbP&>C>(&eDXXx~;9T=LC<7v;NosyR)o~AU5EW>B_fWzqa!q7KfyMe=sLyyZJUeMPhLny%rFMyE&fws}7>0f`P zDHuCe!qA0$z%DuOW!<~AE-Y99^-v zscQ~ct5BXpPGOnZ0icp0?cG8~Ane3zzMdWMyNe}dc6IED=A!MYea5Y&K+AZPEgntH;|%=cBzn72g_uIPVOaii7fvE98yg^ME1*1eBvlvqruINGI?ST} zQW=*vF#rjG&aF2gSVqS|MihSA#-|`AMhyN3pxK?ciPk&C00000NkvXXu0mjf`x~>E literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_5.png b/assets/dolphin/external/L1_Showtime_128x64/frame_5.png new file mode 100755 index 0000000000000000000000000000000000000000..04ad4360ca043b6e1b0f03ccbf4486d2a1c3c5f9 GIT binary patch literal 735 zcmV<50wDc~P)fW?(2=ZBj53F;)+D>@%)A~pyRN?5`~E)f^ZW6BhQs$>lo$aZ zIo3O4Ge~+r^^)SM7}NFaZ+G{WFHXv0IcVOve;udq+I|yiy$5I ztpv!n-{31^XWuu(k?YjHBCd1;;WPjX`CTd5kpt300PHT}$-V;4XgJM`z(W3-V~iq}ddx@W-)!EVhL?0Vf)d=|+YB$3v4@ivjOF=F}!y(AslypZx zI63_Z)^o9$ld=s?dN>7i0&_AE0pa}s$YXrOkASpm1I2mz5$^;LPKV$5>v(dFyH`)+yL4zpIlF12H7a!@Y!VGQu2h1En5n80z3h#^710^0R@j- zge5yp1L!L_6+!ID$t<<{M|uF~WwZp~SK(qj4+mrsfOb$9pbvM;>TH2_JleqoDt@J5 zr~tT79m>wukIj+yf0cQ?Y`r?$2u5BftW?acFAJ)u zymMIARaK2uHFC22p^~gDscNFPHP#De=HR)QLKf6OY%PnPdFWI62*v};?Gk>U0Hy$! z*t_aTwi4m`1(<+;yk0|LsGNDAs`ce3XYJGqJp8fwl8imr)y@G0D5roo{{t&9O!vUn RNK*g+002ovPDHLkV1lW6Sj7MU literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_6.png b/assets/dolphin/external/L1_Showtime_128x64/frame_6.png new file mode 100755 index 0000000000000000000000000000000000000000..86bcbf48c229b985944a3e258d847f239de59c2b GIT binary patch literal 762 zcmVATB?c5)6=T#5*`|e5=CGTzCX;pMeLQS-+WI>_e4gL?^70y<|K_hY z(*U?vjxG6|qVhETNV6lxjQ##|c>K2mG4hCSjslf|SRWHP0VFX1yNy;?{8<7jApoOI zkdf>63y_Duf(OLolm8PheMavA@$op2ECR6Fc%m#vCV91j;X?;iUxuT;04uJ> zzO0`Iwo$NH@Z`ul0D1%7?nUI5H)@?2;^EkYW_!Km$xIs{-iPxt3@2p`fD&k!1CxZq zo#luUmXayuEtNR!e+5gbT?nO04M+!zSEao@!64&p=5U_IgTbTgEhn3k1z@Mm6rSpa z9^}sD*F68|J-|r))?rldb(m`{C)}SlQ+?4;Ro%UAIu|^nIPH}0= z3AxuTI)<2%_j}9b;*|HeDiD@Rx7);-EY^CNx(P2`R+X0)}QPo^kv!KQgDsF2-Rh?ecT+f-M zXFkY@YM=&kZ&UQ$D>3aIFc!RUO!#&lxCDgc_LD$rX+{`FFb}`lV}|H-xB9)R_8;G! s^~+mu<=NsURsYmjiIWP@Ed#gy14n;Zjt)Wng8%>k07*qoM6N<$f*&knYXATM literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Showtime_128x64/frame_7.png b/assets/dolphin/external/L1_Showtime_128x64/frame_7.png new file mode 100755 index 0000000000000000000000000000000000000000..3e2a2c739f21d4a4ab3020e0509a1acee8c3c548 GIT binary patch literal 764 zcmVA$loyp|S#YG(wN^!TV6R$1=tv8#pdjL* zNFht9AThK#_9U~V)PRM?e=*n%nWjRNJ?u2L$?Q5auZP{8w*HPkp6_`--tRNK_TAl( z833}k_t$Ms;J!*Xvd|J^Mt}dw8~?3G3_oX^y@1;%)<;DS0?hz`ok}ATdkzQJ17KtU zWO(IC0_52%@D%al>>jm$_WyzA;tW6qdxO`L)~(rcrnil%YJwbt&ezSWK9CvbovM5WeTN|5 z7Gx{|nu|*hVW*gyWr=KX+>-@hFbr9iS^_k$H-NX=Zh!;{;CeQ2WzZ{w&b0z(yf$*X z{%Bg)H4)~Z<9Y)yGG8cQNwx<381BNxd;qk9(sPF)REmP4*!}WdDYt6`ugwJ8)KlxMv_v?t&*pN)=IWfd3%IC|)zC#~1GTZawH*><4eI`E8ULNZg zt0R|*oM*Q4BY)qCxW8%LJJT;_?q_Vp=2Gr3vC3Z#o7z&rCU1F5ws`q7Pma2t#dmNzO~s{vO5kJSIdky4!C1y!iQFaCZ*bvi13ud3bU uXJ_of7Th?J-=t`t7#-q}0z?Ji&;I~kFkMXW!-@a^0000A$lopG`W1sBVbAeP;#Cl9jFc#H1D{_`NjOBSJ*^%8Pupa;=<%18wj6hu4( z5e%h=vJE!J9!lAS5Cd&#tQbQ(k~IoZ=a7k}$!0qYy6KCGg4j4(@YE_B$ig1z;ybFEcdkpG^8I(bxE5sz9su; z%NQf5Zg=pJpGdnvNPhzqRaH0US!V`KI<`w={~I*gY6poBTVbmsqF*l7XVWcUGb4BN z|9stMj8M2-$hJEE^Ap>3YbUoy!_-t>I4tX`s>Z4sIXUjDBr8j*n&@4P^|F~d_FYUV2WlX;mPId2SE#-Q!*{W$kr!@dWfDjWeII=X4V;t=Vb zG$O@uF{b7HYiH}bIb!)5%WMGBG4Z)YWC!4T08Ho0Rk6CTNjm^E7eSVn784+=@4*sc zbL)S^!5h?<5Led$em?*s`7J3~p99i|0oYo^l^q4_PQRZ4fsy=m+v@7u4(X0LVrH-P z#+?Me?+8F1Yn1)L_)uqCq%VxBYJePo`Yr#V3q-~~R*)+YI|R9(l63*#_w`S~bS^Z* zQnkQNccg%3U|4zsz<*o@@)!^C0wC>JK(Ry{;+_Qjet(5God*J;3+icS88jESLqeht z!1KxswA%n8H-TlCDaREUKxPWq{52W49K9rCNmHRgfGfbPeC`1zP;kiwBxL;=0R0N5 z0|;F?m8IVJNEhIubXEYoS?CE%uuDDwkOXxAT5+1jhYBQdNrEY>c(vG218^im7MN>c zP%0BS7Nwggq2Bz_lq31px)`9HgzBiq3CjuDumqqR)&Cqz0oofyUR8Cv1Pr24(_-lf zG?@L8StueQO#CgyhJbcCUmyCFj0=lFxs&_Y!vfJw+oiV5Ozikmjx5Kib=2ZJmTWY& zZL`Ba;th;6-=%7=nw%fx=c}qrmZyGIV(Ia Date: Mon, 10 Feb 2025 10:44:44 +0000 Subject: [PATCH 02/14] ufbt: bumped action version in example github workflow for project template (#4097) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../project_template/app_template/.github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ufbt/project_template/app_template/.github/workflows/build.yml b/scripts/ufbt/project_template/app_template/.github/workflows/build.yml index 143847c4a..613590d47 100644 --- a/scripts/ufbt/project_template/app_template/.github/workflows/build.yml +++ b/scripts/ufbt/project_template/app_template/.github/workflows/build.yml @@ -34,7 +34,7 @@ jobs: with: sdk-channel: ${{ matrix.sdk-channel }} - name: Upload app artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: # See ufbt action docs for other output variables name: ${{ github.event.repository.name }}-${{ steps.build-app.outputs.suffix }} From 7a92fd359c760ebd2ca07791881fc861805b3366 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Mon, 10 Feb 2025 15:57:16 +0400 Subject: [PATCH 03/14] [FL-3950] Update mbedtls & expose AES (#4092) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update mbedtls * expose mbedtls/aes.h * update f18 Co-authored-by: あく --- lib/mbedtls | 2 +- lib/mbedtls.scons | 2 ++ targets/f18/api_symbols.csv | 26 +++++++++++++++++++++++++- targets/f7/api_symbols.csv | 26 +++++++++++++++++++++++++- 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/lib/mbedtls b/lib/mbedtls index edb8fec98..107ea89da 160000 --- a/lib/mbedtls +++ b/lib/mbedtls @@ -1 +1 @@ -Subproject commit edb8fec9882084344a314368ac7fd957a187519c +Subproject commit 107ea89daaefb9867ea9121002fbbdf926780e98 diff --git a/lib/mbedtls.scons b/lib/mbedtls.scons index 77add7696..759f263af 100644 --- a/lib/mbedtls.scons +++ b/lib/mbedtls.scons @@ -6,6 +6,7 @@ env.Append( "#/lib/mbedtls/include", ], SDK_HEADERS=[ + File("mbedtls/include/mbedtls/aes.h"), File("mbedtls/include/mbedtls/des.h"), File("mbedtls/include/mbedtls/sha1.h"), File("mbedtls/include/mbedtls/sha256.h"), @@ -37,6 +38,7 @@ libenv.AppendUnique( # sources = libenv.GlobRecursive("*.c*", "mbedtls/library") # Otherwise, we can just use the files we need: sources = [ + File("mbedtls/library/aes.c"), File("mbedtls/library/bignum.c"), File("mbedtls/library/bignum_core.c"), File("mbedtls/library/ecdsa.c"), diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 0a4b7dde6..29ed764e8 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -84,6 +84,7 @@ Header,+,lib/libusb_stm32/inc/usb_hid.h,, Header,+,lib/libusb_stm32/inc/usb_std.h,, Header,+,lib/libusb_stm32/inc/usb_tmc.h,, Header,+,lib/libusb_stm32/inc/usbd_core.h,, +Header,+,lib/mbedtls/include/mbedtls/aes.h,, Header,+,lib/mbedtls/include/mbedtls/des.h,, Header,+,lib/mbedtls/include/mbedtls/ecdh.h,, Header,+,lib/mbedtls/include/mbedtls/ecdsa.h,, @@ -1891,6 +1892,21 @@ Function,+,manchester_encoder_advance,_Bool,"ManchesterEncoderState*, const _Boo Function,+,manchester_encoder_finish,ManchesterEncoderResult,ManchesterEncoderState* Function,+,manchester_encoder_reset,void,ManchesterEncoderState* Function,+,maxim_crc8,uint8_t,"const uint8_t*, const uint8_t, const uint8_t" +Function,-,mbedtls_aes_crypt_cbc,int,"mbedtls_aes_context*, int, size_t, unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_crypt_cfb128,int,"mbedtls_aes_context*, int, size_t, size_t*, unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_crypt_cfb8,int,"mbedtls_aes_context*, int, size_t, unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_crypt_ctr,int,"mbedtls_aes_context*, size_t, size_t*, unsigned char[16], unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_crypt_ecb,int,"mbedtls_aes_context*, int, const unsigned char[16], unsigned char[16]" +Function,-,mbedtls_aes_crypt_ofb,int,"mbedtls_aes_context*, size_t, size_t*, unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_crypt_xts,int,"mbedtls_aes_xts_context*, int, size_t, const unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_free,void,mbedtls_aes_context* +Function,-,mbedtls_aes_init,void,mbedtls_aes_context* +Function,-,mbedtls_aes_setkey_dec,int,"mbedtls_aes_context*, const unsigned char*, unsigned int" +Function,-,mbedtls_aes_setkey_enc,int,"mbedtls_aes_context*, const unsigned char*, unsigned int" +Function,-,mbedtls_aes_xts_free,void,mbedtls_aes_xts_context* +Function,-,mbedtls_aes_xts_init,void,mbedtls_aes_xts_context* +Function,-,mbedtls_aes_xts_setkey_dec,int,"mbedtls_aes_xts_context*, const unsigned char*, unsigned int" +Function,-,mbedtls_aes_xts_setkey_enc,int,"mbedtls_aes_xts_context*, const unsigned char*, unsigned int" Function,-,mbedtls_des3_crypt_cbc,int,"mbedtls_des3_context*, int, size_t, unsigned char[8], const unsigned char*, unsigned char*" Function,-,mbedtls_des3_crypt_ecb,int,"mbedtls_des3_context*, const unsigned char[8], unsigned char[8]" Function,-,mbedtls_des3_free,void,mbedtls_des3_context* @@ -1914,6 +1930,7 @@ Function,-,mbedtls_ecdh_can_do,int,mbedtls_ecp_group_id Function,-,mbedtls_ecdh_compute_shared,int,"mbedtls_ecp_group*, mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" Function,-,mbedtls_ecdh_free,void,mbedtls_ecdh_context* Function,-,mbedtls_ecdh_gen_public,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_get_grp_id,mbedtls_ecp_group_id,mbedtls_ecdh_context* Function,-,mbedtls_ecdh_get_params,int,"mbedtls_ecdh_context*, const mbedtls_ecp_keypair*, mbedtls_ecdh_side" Function,-,mbedtls_ecdh_init,void,mbedtls_ecdh_context* Function,-,mbedtls_ecdh_make_params,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" @@ -1954,7 +1971,9 @@ Function,-,mbedtls_ecp_group_init,void,mbedtls_ecp_group* Function,-,mbedtls_ecp_group_load,int,"mbedtls_ecp_group*, mbedtls_ecp_group_id" Function,-,mbedtls_ecp_grp_id_list,const mbedtls_ecp_group_id*, Function,-,mbedtls_ecp_is_zero,int,mbedtls_ecp_point* +Function,-,mbedtls_ecp_keypair_calc_public,int,"mbedtls_ecp_keypair*, int (*)(void*, unsigned char*, size_t), void*" Function,-,mbedtls_ecp_keypair_free,void,mbedtls_ecp_keypair* +Function,-,mbedtls_ecp_keypair_get_group_id,mbedtls_ecp_group_id,const mbedtls_ecp_keypair* Function,-,mbedtls_ecp_keypair_init,void,mbedtls_ecp_keypair* Function,-,mbedtls_ecp_mul,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" Function,-,mbedtls_ecp_mul_restartable,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecp_restart_ctx*" @@ -1967,6 +1986,7 @@ Function,-,mbedtls_ecp_point_read_binary,int,"const mbedtls_ecp_group*, mbedtls_ Function,-,mbedtls_ecp_point_read_string,int,"mbedtls_ecp_point*, int, const char*, const char*" Function,-,mbedtls_ecp_point_write_binary,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" Function,-,mbedtls_ecp_read_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, const unsigned char*, size_t" +Function,-,mbedtls_ecp_set_public_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, const mbedtls_ecp_point*" Function,-,mbedtls_ecp_set_zero,int,mbedtls_ecp_point* Function,-,mbedtls_ecp_tls_read_group,int,"mbedtls_ecp_group*, const unsigned char**, size_t" Function,-,mbedtls_ecp_tls_read_group_id,int,"mbedtls_ecp_group_id*, const unsigned char**, size_t" @@ -1974,6 +1994,10 @@ Function,-,mbedtls_ecp_tls_read_point,int,"const mbedtls_ecp_group*, mbedtls_ecp Function,-,mbedtls_ecp_tls_write_group,int,"const mbedtls_ecp_group*, size_t*, unsigned char*, size_t" Function,-,mbedtls_ecp_tls_write_point,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" Function,-,mbedtls_ecp_write_key,int,"mbedtls_ecp_keypair*, unsigned char*, size_t" +Function,-,mbedtls_ecp_write_key_ext,int,"const mbedtls_ecp_keypair*, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_write_public_key,int,"const mbedtls_ecp_keypair*, int, size_t*, unsigned char*, size_t" +Function,-,mbedtls_internal_aes_decrypt,int,"mbedtls_aes_context*, const unsigned char[16], unsigned char[16]" +Function,-,mbedtls_internal_aes_encrypt,int,"mbedtls_aes_context*, const unsigned char[16], unsigned char[16]" Function,-,mbedtls_internal_md5_process,int,"mbedtls_md5_context*, const unsigned char[64]" Function,-,mbedtls_internal_sha1_process,int,"mbedtls_sha1_context*, const unsigned char[64]" Function,-,mbedtls_internal_sha256_process,int,"mbedtls_sha256_context*, const unsigned char[64]" @@ -2302,9 +2326,9 @@ Function,+,pipe_install_as_stdio,void,PipeSide* Function,+,pipe_receive,size_t,"PipeSide*, void*, size_t, FuriWait" Function,+,pipe_role,PipeRole,PipeSide* Function,+,pipe_send,size_t,"PipeSide*, const void*, size_t, FuriWait" +Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, FuriEventLoopEvent" Function,+,pipe_set_callback_context,void,"PipeSide*, void*" Function,+,pipe_set_data_arrived_callback,void,"PipeSide*, PipeSideDataArrivedCallback, FuriEventLoopEvent" -Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, FuriEventLoopEvent" Function,+,pipe_set_space_freed_callback,void,"PipeSide*, PipeSideSpaceFreedCallback, FuriEventLoopEvent" Function,+,pipe_spaces_available,size_t,PipeSide* Function,+,pipe_state,PipeState,PipeSide* diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 15f4d70d7..4a385d538 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -96,6 +96,7 @@ Header,+,lib/libusb_stm32/inc/usb_hid.h,, Header,+,lib/libusb_stm32/inc/usb_std.h,, Header,+,lib/libusb_stm32/inc/usb_tmc.h,, Header,+,lib/libusb_stm32/inc/usbd_core.h,, +Header,+,lib/mbedtls/include/mbedtls/aes.h,, Header,+,lib/mbedtls/include/mbedtls/des.h,, Header,+,lib/mbedtls/include/mbedtls/ecdh.h,, Header,+,lib/mbedtls/include/mbedtls/ecdsa.h,, @@ -2317,6 +2318,21 @@ Function,+,manchester_encoder_advance,_Bool,"ManchesterEncoderState*, const _Boo Function,+,manchester_encoder_finish,ManchesterEncoderResult,ManchesterEncoderState* Function,+,manchester_encoder_reset,void,ManchesterEncoderState* Function,+,maxim_crc8,uint8_t,"const uint8_t*, const uint8_t, const uint8_t" +Function,-,mbedtls_aes_crypt_cbc,int,"mbedtls_aes_context*, int, size_t, unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_crypt_cfb128,int,"mbedtls_aes_context*, int, size_t, size_t*, unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_crypt_cfb8,int,"mbedtls_aes_context*, int, size_t, unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_crypt_ctr,int,"mbedtls_aes_context*, size_t, size_t*, unsigned char[16], unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_crypt_ecb,int,"mbedtls_aes_context*, int, const unsigned char[16], unsigned char[16]" +Function,-,mbedtls_aes_crypt_ofb,int,"mbedtls_aes_context*, size_t, size_t*, unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_crypt_xts,int,"mbedtls_aes_xts_context*, int, size_t, const unsigned char[16], const unsigned char*, unsigned char*" +Function,-,mbedtls_aes_free,void,mbedtls_aes_context* +Function,-,mbedtls_aes_init,void,mbedtls_aes_context* +Function,-,mbedtls_aes_setkey_dec,int,"mbedtls_aes_context*, const unsigned char*, unsigned int" +Function,-,mbedtls_aes_setkey_enc,int,"mbedtls_aes_context*, const unsigned char*, unsigned int" +Function,-,mbedtls_aes_xts_free,void,mbedtls_aes_xts_context* +Function,-,mbedtls_aes_xts_init,void,mbedtls_aes_xts_context* +Function,-,mbedtls_aes_xts_setkey_dec,int,"mbedtls_aes_xts_context*, const unsigned char*, unsigned int" +Function,-,mbedtls_aes_xts_setkey_enc,int,"mbedtls_aes_xts_context*, const unsigned char*, unsigned int" Function,-,mbedtls_des3_crypt_cbc,int,"mbedtls_des3_context*, int, size_t, unsigned char[8], const unsigned char*, unsigned char*" Function,-,mbedtls_des3_crypt_ecb,int,"mbedtls_des3_context*, const unsigned char[8], unsigned char[8]" Function,-,mbedtls_des3_free,void,mbedtls_des3_context* @@ -2340,6 +2356,7 @@ Function,-,mbedtls_ecdh_can_do,int,mbedtls_ecp_group_id Function,-,mbedtls_ecdh_compute_shared,int,"mbedtls_ecp_group*, mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" Function,-,mbedtls_ecdh_free,void,mbedtls_ecdh_context* Function,-,mbedtls_ecdh_gen_public,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_get_grp_id,mbedtls_ecp_group_id,mbedtls_ecdh_context* Function,-,mbedtls_ecdh_get_params,int,"mbedtls_ecdh_context*, const mbedtls_ecp_keypair*, mbedtls_ecdh_side" Function,-,mbedtls_ecdh_init,void,mbedtls_ecdh_context* Function,-,mbedtls_ecdh_make_params,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" @@ -2380,7 +2397,9 @@ Function,-,mbedtls_ecp_group_init,void,mbedtls_ecp_group* Function,-,mbedtls_ecp_group_load,int,"mbedtls_ecp_group*, mbedtls_ecp_group_id" Function,-,mbedtls_ecp_grp_id_list,const mbedtls_ecp_group_id*, Function,-,mbedtls_ecp_is_zero,int,mbedtls_ecp_point* +Function,-,mbedtls_ecp_keypair_calc_public,int,"mbedtls_ecp_keypair*, int (*)(void*, unsigned char*, size_t), void*" Function,-,mbedtls_ecp_keypair_free,void,mbedtls_ecp_keypair* +Function,-,mbedtls_ecp_keypair_get_group_id,mbedtls_ecp_group_id,const mbedtls_ecp_keypair* Function,-,mbedtls_ecp_keypair_init,void,mbedtls_ecp_keypair* Function,-,mbedtls_ecp_mul,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" Function,-,mbedtls_ecp_mul_restartable,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecp_restart_ctx*" @@ -2393,6 +2412,7 @@ Function,-,mbedtls_ecp_point_read_binary,int,"const mbedtls_ecp_group*, mbedtls_ Function,-,mbedtls_ecp_point_read_string,int,"mbedtls_ecp_point*, int, const char*, const char*" Function,-,mbedtls_ecp_point_write_binary,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" Function,-,mbedtls_ecp_read_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, const unsigned char*, size_t" +Function,-,mbedtls_ecp_set_public_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, const mbedtls_ecp_point*" Function,-,mbedtls_ecp_set_zero,int,mbedtls_ecp_point* Function,-,mbedtls_ecp_tls_read_group,int,"mbedtls_ecp_group*, const unsigned char**, size_t" Function,-,mbedtls_ecp_tls_read_group_id,int,"mbedtls_ecp_group_id*, const unsigned char**, size_t" @@ -2400,6 +2420,10 @@ Function,-,mbedtls_ecp_tls_read_point,int,"const mbedtls_ecp_group*, mbedtls_ecp Function,-,mbedtls_ecp_tls_write_group,int,"const mbedtls_ecp_group*, size_t*, unsigned char*, size_t" Function,-,mbedtls_ecp_tls_write_point,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" Function,-,mbedtls_ecp_write_key,int,"mbedtls_ecp_keypair*, unsigned char*, size_t" +Function,-,mbedtls_ecp_write_key_ext,int,"const mbedtls_ecp_keypair*, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_write_public_key,int,"const mbedtls_ecp_keypair*, int, size_t*, unsigned char*, size_t" +Function,-,mbedtls_internal_aes_decrypt,int,"mbedtls_aes_context*, const unsigned char[16], unsigned char[16]" +Function,-,mbedtls_internal_aes_encrypt,int,"mbedtls_aes_context*, const unsigned char[16], unsigned char[16]" Function,-,mbedtls_internal_md5_process,int,"mbedtls_md5_context*, const unsigned char[64]" Function,-,mbedtls_internal_sha1_process,int,"mbedtls_sha1_context*, const unsigned char[64]" Function,-,mbedtls_internal_sha256_process,int,"mbedtls_sha256_context*, const unsigned char[64]" @@ -2938,9 +2962,9 @@ Function,+,pipe_install_as_stdio,void,PipeSide* Function,+,pipe_receive,size_t,"PipeSide*, void*, size_t, FuriWait" Function,+,pipe_role,PipeRole,PipeSide* Function,+,pipe_send,size_t,"PipeSide*, const void*, size_t, FuriWait" +Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, FuriEventLoopEvent" Function,+,pipe_set_callback_context,void,"PipeSide*, void*" Function,+,pipe_set_data_arrived_callback,void,"PipeSide*, PipeSideDataArrivedCallback, FuriEventLoopEvent" -Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, FuriEventLoopEvent" Function,+,pipe_set_space_freed_callback,void,"PipeSide*, PipeSideSpaceFreedCallback, FuriEventLoopEvent" Function,+,pipe_spaces_available,size_t,PipeSide* Function,+,pipe_state,PipeState,PipeSide* From f05302813af8768cefa686d02090b307e8d28ea8 Mon Sep 17 00:00:00 2001 From: A0i Date: Tue, 11 Feb 2025 23:58:19 +1300 Subject: [PATCH 04/14] Add new AC for Fujitsu ASTG12LVCC (#4095) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add new AC for Fujitsu ASTG12LVCC * Updated timeout settings in GitHub Actions workflow * Revert CI changes Co-authored-by: Banana Blue Co-authored-by: あく --- .../infrared/resources/infrared/assets/ac.ir | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/applications/main/infrared/resources/infrared/assets/ac.ir b/applications/main/infrared/resources/infrared/assets/ac.ir index f57fe3aa1..96b4eb1c8 100644 --- a/applications/main/infrared/resources/infrared/assets/ac.ir +++ b/applications/main/infrared/resources/infrared/assets/ac.ir @@ -1896,3 +1896,42 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 9024 4481 655 551 655 1653 654 550 656 1652 655 1652 656 550 656 550 656 550 656 550 656 551 655 1652 655 551 655 1652 655 550 656 551 655 1654 654 550 656 550 656 551 655 1652 655 550 656 551 654 550 656 1652 655 1651 657 550 655 551 655 550 656 1654 654 550 656 1653 654 551 654 551 655 1651 656 551 655 19984 655 550 656 551 655 550 656 551 655 550 655 551 655 551 655 550 656 1654 653 1653 655 1653 655 550 655 551 655 550 656 551 655 551 655 550 656 551 655 551 655 551 655 551 655 551 655 550 656 550 656 550 656 551 655 551 655 551 655 1652 656 550 656 551 655 550 656 39996 8999 4479 656 551 655 1652 656 550 656 1653 655 1653 655 550 656 551 655 550 656 551 655 551 655 1652 655 551 655 1652 655 550 656 551 655 1653 655 551 655 550 656 550 656 1652 655 551 654 551 655 551 655 1652 655 1652 656 551 655 551 655 552 654 551 655 1653 655 1653 655 551 655 549 656 1653 655 552 654 19984 655 1652 655 551 655 550 656 1652 656 551 655 551 655 551 655 1652 655 1652 655 551 656 1652 656 1653 655 1653 655 551 655 1652 655 551 655 551 655 551 654 551 654 551 655 551 655 1653 655 550 656 551 655 1652 656 1653 654 551 655 551 655 551 655 550 655 550 656 551 655 +# +# Model: Fujitsu ASTG12LVCC +# +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3258 1573 427 404 426 404 425 1180 428 403 427 1183 425 402 427 402 428 402 427 1180 428 1181 427 404 426 403 427 402 428 1181 427 1181 427 402 427 405 425 402 427 402 427 403 427 402 428 402 428 403 426 401 429 403 427 402 428 403 427 403 427 1180 428 401 428 404 425 401 428 402 427 402 427 402 427 402 428 1180 427 401 428 403 427 402 427 401 428 1180 427 401 428 402 427 402 428 402 427 401 428 403 427 1180 427 402 427 1180 427 1180 427 1177 429 1179 427 1179 427 1178 428 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 39677 99167 3233 1570 425 405 425 404 425 1184 424 405 425 1182 426 405 424 404 426 404 425 1181 427 1182 426 403 427 403 426 404 426 1183 425 1183 425 403 426 404 426 406 424 404 425 405 425 402 427 405 425 404 425 403 426 404 426 404 425 402 427 405 424 1182 425 402 427 404 426 403 426 404 425 404 426 404 425 404 425 1183 424 406 423 404 426 403 426 404 425 1181 427 1182 426 1181 426 1181 426 1181 425 1182 425 1181 426 1182 426 403 426 404 425 1182 426 404 425 404 425 405 425 404 426 403 426 403 427 404 426 404 426 1182 426 1182 426 403 426 404 426 1182 426 405 424 404 426 403 426 1182 426 405 425 403 426 1182 426 404 426 1183 425 403 426 403 426 404 425 403 426 405 425 403 426 1182 425 1182 425 403 427 404 425 1181 426 403 427 403 426 404 425 406 424 404 426 404 425 404 426 404 425 404 426 404 426 404 426 404 426 404 425 404 426 404 426 403 426 403 427 404 425 402 427 405 425 403 426 404 425 404 425 404 425 405 425 404 425 404 425 404 426 403 426 402 427 403 427 403 426 1182 425 404 426 404 425 403 426 1182 425 403 426 1181 426 403 427 403 426 404 425 405 425 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 39674 99137 3228 1573 422 407 421 408 422 1185 423 408 422 1187 421 410 419 409 421 408 421 1186 422 1187 421 408 421 408 422 409 421 1187 420 1186 422 408 421 410 419 407 424 408 421 407 421 410 420 409 421 408 422 408 421 408 422 407 422 410 419 408 422 1187 420 408 421 408 422 408 421 408 421 408 421 408 420 409 421 1187 444 382 422 408 422 408 421 408 445 1162 419 1187 420 1184 423 1185 421 1184 423 1186 421 1186 421 1187 422 409 419 409 420 1186 422 407 420 409 422 409 420 407 422 407 422 411 419 406 421 409 422 1185 446 1162 420 409 421 409 421 1189 418 407 421 408 422 407 422 409 420 409 421 408 420 412 417 1187 421 407 422 408 420 410 421 408 421 409 421 409 445 384 420 410 421 407 421 407 422 409 421 1187 420 409 419 409 421 408 422 408 421 410 419 409 420 410 419 410 420 407 422 409 420 408 421 407 422 408 421 408 421 410 419 409 420 407 423 407 422 409 421 410 419 411 418 408 421 408 422 410 420 407 421 409 419 409 421 409 419 408 422 407 422 407 422 409 420 1188 419 409 421 409 420 409 419 1189 419 1186 421 1188 419 1187 420 408 421 407 422 1188 419 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 39689 99188 3229 1576 421 407 422 409 420 1188 419 409 421 1187 422 408 422 409 419 410 419 1187 422 1186 423 410 419 409 421 409 420 1187 420 1188 420 410 447 382 420 409 422 410 446 383 422 409 420 407 422 410 395 435 420 408 422 407 422 410 420 409 445 1162 420 410 420 409 420 410 420 409 421 410 419 409 421 409 419 1189 420 407 422 409 395 437 419 410 418 1186 422 1186 423 1187 420 1185 422 1188 420 1184 421 1188 419 1188 419 408 420 410 419 1186 421 408 420 410 419 410 419 409 419 411 418 409 421 410 419 409 420 1187 445 1163 419 412 417 409 420 1188 419 409 419 410 420 409 444 1164 418 1187 419 1189 419 409 419 1187 420 408 422 409 419 410 420 409 419 410 419 434 393 411 420 409 421 408 421 409 419 409 421 1188 418 410 419 410 420 410 418 412 417 409 445 385 419 409 420 410 420 408 419 409 421 410 419 411 419 408 446 382 421 409 420 409 420 410 418 409 420 409 419 410 419 412 442 384 419 411 416 412 419 409 420 410 419 410 419 410 418 410 420 409 420 409 420 434 394 1187 419 412 417 410 418 410 420 1188 419 1187 420 1188 419 410 419 1188 419 411 418 434 396 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 39692 99118 3226 1571 423 406 423 405 423 1185 421 405 424 1183 423 406 422 408 422 405 423 1184 446 1160 422 409 420 406 424 405 424 1185 422 1183 424 404 425 406 422 408 421 406 423 407 422 406 423 407 421 406 424 407 422 407 422 404 425 407 421 409 420 1185 422 406 423 408 421 404 424 405 424 407 447 383 421 406 424 1184 447 380 424 406 422 409 421 407 423 1183 447 1159 424 1185 422 1185 421 1184 422 1185 422 1185 421 1185 423 407 423 406 423 1185 423 406 424 406 423 408 446 381 424 406 423 408 421 406 424 406 423 1185 423 1184 422 407 423 407 422 1187 421 408 421 407 423 407 423 405 424 1185 422 1186 421 1184 423 407 422 407 422 1186 422 407 422 406 423 408 422 405 423 408 447 383 420 409 421 406 423 407 423 1184 423 407 423 407 422 408 421 408 423 406 424 406 422 409 422 406 423 408 421 408 421 406 422 406 424 407 422 406 423 409 421 407 422 408 423 406 423 406 423 409 446 382 447 384 420 407 423 405 424 406 423 406 423 407 423 407 422 406 423 405 422 407 424 406 422 1185 422 406 423 407 422 1183 423 1184 422 407 422 1185 423 1186 421 1184 424 407 422 1185 422 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 39670 99106 3227 1570 424 406 422 407 422 1183 424 405 424 1184 448 380 423 407 421 406 424 1183 424 1185 421 406 423 404 424 405 424 1184 423 1182 425 407 448 380 423 407 422 405 423 406 422 406 424 405 423 407 421 406 423 407 422 405 424 405 423 406 423 1184 422 408 421 408 422 405 424 406 421 407 422 406 423 405 423 1183 424 406 423 405 423 405 423 405 423 1186 421 1184 422 1184 422 1185 422 1184 447 1159 423 1184 422 1184 422 408 421 407 423 1184 421 407 448 381 422 405 423 409 421 406 422 406 422 407 422 406 423 1183 423 1185 422 406 423 405 424 1184 423 408 421 405 424 405 424 1184 422 1185 422 1184 422 407 423 408 420 409 420 1185 447 382 423 405 423 408 421 406 423 407 422 406 423 406 423 408 421 406 423 1183 424 407 422 406 424 405 424 406 423 407 423 406 423 408 422 407 422 405 424 408 421 407 422 407 422 406 423 406 423 407 422 406 423 406 422 408 421 407 422 408 421 407 422 406 423 408 422 406 423 405 423 409 422 406 422 406 423 406 423 407 422 407 423 405 424 1184 423 407 421 406 424 1184 423 1184 422 407 423 1183 423 405 424 1184 423 409 420 407 422 +# From a2b81e4e37e1e0c216aee8cace01ecafa0ffb12c Mon Sep 17 00:00:00 2001 From: jay candel Date: Tue, 11 Feb 2025 22:54:11 +0800 Subject: [PATCH 05/14] Infrared: Update TV universal (#4080) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update tv.ir * Infrared: cleanup tv.ir merge artifacts Co-authored-by: あく --- .../infrared/resources/infrared/assets/tv.ir | 1176 +++++++++++++++++ 1 file changed, 1176 insertions(+) diff --git a/applications/main/infrared/resources/infrared/assets/tv.ir b/applications/main/infrared/resources/infrared/assets/tv.ir index ae3c4d4b4..6311f500c 100644 --- a/applications/main/infrared/resources/infrared/assets/tv.ir +++ b/applications/main/infrared/resources/infrared/assets/tv.ir @@ -3657,3 +3657,1179 @@ type: parsed protocol: NECext address: AD ED 00 00 command: C5 3A 00 00 +# +# Model: AKAI ATE_22Y604W +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9292 4518 635 522 635 522 635 523 634 523 662 494 664 494 663 1625 661 519 662 1602 660 1626 660 1650 636 1650 636 1651 635 1651 635 522 634 1653 633 524 633 1655 631 526 631 527 630 1657 630 527 630 527 630 527 630 1658 630 527 630 1658 630 1658 630 527 631 1658 629 1658 629 1658 629 40773 9295 2239 630 98164 9297 2241 630 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9319 4500 657 499 658 498 660 498 659 500 658 498 660 499 688 1600 685 472 634 1654 634 1680 607 1681 607 1681 607 1681 607 1680 608 549 609 1680 608 550 608 1681 607 550 607 1682 631 1657 631 527 631 527 631 527 631 1658 631 527 631 1659 630 527 631 528 630 1659 630 1659 630 1658 631 40798 9302 2242 630 98247 9298 2243 631 98266 9301 2243 630 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9335 4533 632 501 659 499 660 499 660 500 660 501 658 500 689 1604 685 474 635 1683 608 1659 632 1683 608 1684 607 1684 608 1684 608 551 609 1683 609 551 609 1684 608 1684 608 1685 607 1685 632 528 632 528 632 528 632 1661 631 529 631 529 631 529 631 529 631 1662 631 1662 631 1662 631 40877 9313 2247 631 98424 9314 2248 631 98437 9314 2247 632 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9305 4503 660 498 690 470 688 470 687 473 635 524 635 524 635 1657 634 525 663 1629 662 1630 659 1655 609 1682 609 1682 609 1682 633 525 635 1657 634 525 634 525 634 526 633 527 632 1660 631 528 632 528 631 528 631 1661 631 1661 631 1661 631 1660 631 528 631 1661 631 1661 630 1661 630 40849 9309 2243 631 98361 9313 2244 631 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9338 4507 658 500 689 470 688 471 636 525 635 525 635 524 636 1658 635 525 663 1655 637 1630 661 1655 635 1657 635 1657 636 1657 635 524 635 1658 635 1658 634 1658 634 526 634 1660 632 1661 632 528 632 528 632 528 632 528 632 528 632 1662 631 528 632 528 632 1662 631 1662 631 1662 631 40877 9317 2245 631 98426 9319 2246 631 +# +# Model: Brandt B3230HD_TV +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9344 4504 663 494 666 494 666 495 665 496 663 521 638 522 637 1634 660 522 638 1633 660 1655 638 1656 636 1656 636 1657 636 1658 635 526 633 1661 632 1662 631 1662 631 1663 631 1663 631 1662 632 530 631 530 631 530 630 530 631 530 631 530 631 530 631 530 631 1663 631 1664 630 1663 631 40893 9321 2247 631 98484 9323 2247 632 +# +# Model: BUSH TV_VL32HDLED +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9028 4480 593 1667 589 541 597 532 596 534 594 562 566 564 564 539 589 567 571 558 570 1663 594 1666 591 1696 571 1662 595 1666 591 1669 598 1662 595 562 566 563 565 539 589 567 571 1661 596 561 567 563 565 564 564 1669 598 1662 595 1691 566 1668 599 558 570 1663 594 1692 565 575 1669 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9200 4445 656 510 628 511 626 1616 626 514 623 542 597 542 597 542 597 542 597 1648 596 1648 596 543 596 1648 596 1648 596 1648 596 1648 596 1648 596 543 596 543 595 1649 595 1648 596 543 595 544 596 543 594 545 596 1648 595 1649 593 545 595 543 595 1650 595 1648 595 1649 595 1649 595 39850 9193 2218 595 95963 9218 2218 596 95989 9193 2219 595 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9226 4417 657 508 628 511 625 1617 624 515 622 517 622 517 621 517 622 517 622 1622 621 1623 620 518 621 1622 622 1623 620 1623 621 1623 621 1623 620 518 621 518 620 518 621 1623 621 1623 619 519 620 518 620 518 621 1624 620 1623 595 1649 619 519 620 519 619 1625 619 1648 596 1625 594 39874 9194 2192 620 95968 9197 2242 571 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9205 4446 630 536 628 511 627 1616 626 539 598 542 597 542 597 542 597 542 597 1647 597 1647 597 542 597 1647 597 1648 596 1648 596 1648 596 1648 596 1648 596 1648 596 542 597 1648 596 542 597 542 597 543 597 542 597 542 597 543 597 1648 596 543 596 1648 596 1648 596 1648 596 1648 596 39850 9202 2218 596 95967 9230 2217 597 +# +# Model: ContinentalEdison +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9209 4446 655 512 628 510 628 1616 626 515 622 542 597 542 597 542 597 542 597 1648 596 1648 597 542 597 1647 597 1647 597 1647 597 1647 597 1647 597 1648 596 542 597 1648 596 542 597 1648 597 542 597 542 597 542 597 542 597 1648 596 543 596 1648 597 543 596 1648 596 1648 597 1648 596 39847 9203 2218 596 95986 9203 2218 596 95964 9230 2218 596 95965 9232 2218 596 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9225 4476 586 1675 613 527 612 529 610 530 609 532 607 558 581 558 582 559 581 559 581 1681 581 1681 581 1681 581 1681 581 1681 581 1681 581 1681 581 1683 581 1681 581 1681 581 1681 581 559 581 559 581 558 582 559 580 559 581 559 581 559 581 559 581 1681 581 1681 581 1682 580 1682 581 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 337 1695 339 664 340 664 339 665 338 664 339 693 310 1695 339 1696 338 693 310 1697 337 666 337 693 310 693 310 1723 311 692 311 44457 309 1723 310 692 311 692 311 692 311 693 310 1723 310 694 334 669 334 1700 333 672 331 1703 330 1727 306 1704 330 697 306 1727 306 42378 309 1724 333 670 333 670 333 672 331 673 330 673 330 1704 329 1704 329 674 329 1727 306 698 305 698 305 698 305 1728 305 698 305 44436 309 1724 334 670 333 671 332 672 331 697 306 1728 306 674 329 697 306 1728 306 698 306 1728 306 1727 306 1728 305 698 305 1727 306 42378 309 1724 334 669 334 671 332 672 330 673 330 697 306 1703 330 1727 306 697 306 1727 306 697 306 698 305 697 306 1728 305 697 306 44431 309 1724 334 670 333 670 333 672 331 696 306 1727 306 697 306 697 306 1727 306 697 306 1727 306 1727 306 1727 306 697 306 1728 305 42373 309 1724 334 670 333 670 333 671 332 697 306 697 306 1727 305 1727 306 697 306 1728 305 697 306 697 306 697 306 1727 306 697 306 44427 309 1724 334 669 334 670 333 672 331 697 306 1728 306 697 306 697 306 1727 306 697 306 1727 306 1727 306 1727 306 697 306 1728 305 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 336 1697 336 667 336 668 335 668 336 667 337 1696 338 1696 337 1696 337 667 336 1697 337 668 335 668 335 669 334 1699 334 693 309 43422 335 1723 310 694 309 694 309 695 333 671 332 672 331 673 331 673 331 1704 330 673 330 1703 331 1704 330 1703 331 673 331 1704 330 43424 309 1725 308 695 308 696 332 672 332 673 331 1703 331 1703 330 1703 331 673 331 1703 331 673 331 673 330 673 331 1703 331 673 331 43418 308 1725 308 695 333 671 332 672 331 672 331 673 331 673 330 673 330 1703 331 673 331 1703 331 1704 330 1703 331 673 330 1703 331 43418 309 1725 308 695 308 696 332 672 331 673 330 1703 331 1703 331 1703 331 673 331 1703 330 673 330 673 330 673 331 1703 331 673 331 43419 308 1725 308 695 308 696 307 697 331 673 331 672 331 672 331 673 330 1703 331 673 330 1703 331 1703 331 1703 331 673 331 1703 331 43419 309 1725 308 695 308 696 332 672 331 673 330 1703 331 1703 331 1703 331 673 330 1704 330 673 330 673 330 673 330 1703 331 673 330 43424 309 1725 309 695 333 671 332 672 331 672 331 673 331 673 330 673 331 1703 331 673 331 1703 331 1704 330 1703 331 672 332 1703 331 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 310 1696 337 664 339 693 310 693 310 665 338 666 337 665 338 1696 338 665 338 1723 310 666 337 693 310 693 310 1723 310 693 310 45493 309 1724 309 693 310 693 310 692 311 692 311 1722 311 1723 310 693 310 1724 334 669 334 1700 331 1701 308 1727 331 673 330 1703 330 41342 333 1699 334 670 333 670 333 671 332 672 331 671 332 672 331 1702 331 671 332 1702 331 672 331 672 331 672 331 1702 331 672 331 45459 333 1699 334 670 333 671 332 696 306 673 331 1701 332 1702 331 672 331 1702 331 672 331 1702 331 1702 331 1701 332 672 331 1702 331 +# +# Model: Grandin +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 337 1698 336 667 336 665 338 666 337 665 392 1644 337 666 338 1696 338 666 338 1723 310 667 337 667 336 693 310 1723 311 692 311 44474 310 1723 310 692 311 692 311 693 310 693 310 694 309 1725 334 670 333 1701 332 672 332 1702 331 1702 332 1702 331 672 332 1702 331 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 970 719 972 718 1822 718 944 747 920 771 921 799 893 802 893 799 893 1644 893 799 1767 770 918 86138 893 798 894 798 1768 772 915 778 913 779 913 804 888 807 888 804 888 1627 911 805 1737 801 888 86143 893 798 918 774 1766 775 913 780 912 780 912 779 913 783 912 780 912 1625 913 780 1763 777 912 86141 892 798 918 774 1766 776 912 780 911 780 912 780 912 783 912 780 912 1626 912 780 1762 801 888 86137 892 799 917 774 1766 775 913 780 912 780 912 779 913 783 912 781 911 1650 888 805 1738 801 887 86148 892 799 918 775 1765 800 888 804 888 804 888 804 888 808 888 804 888 1651 888 805 1738 801 888 86133 944 772 919 773 1767 774 914 778 914 778 914 778 914 781 915 777 915 1624 914 778 1766 774 914 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 972 719 1823 716 973 719 972 720 945 747 920 772 920 802 893 1645 1743 796 918 773 918 774 916 86148 917 774 1767 772 916 777 914 778 913 779 913 779 913 783 913 1625 1763 776 913 779 913 779 913 86148 918 773 1767 773 915 778 914 779 913 779 913 780 912 783 913 1625 1764 777 912 780 912 780 912 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 946 745 947 745 1850 688 945 746 944 748 893 798 893 802 893 1644 1743 794 894 797 894 1643 918 85284 892 798 894 798 1769 769 918 775 915 778 914 778 914 782 913 1649 1739 775 913 778 914 1625 913 85274 943 771 919 773 1766 773 915 778 914 777 915 777 915 781 914 1623 1765 774 914 778 914 1623 914 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 972 719 1822 715 972 717 973 719 970 721 919 772 919 1647 1743 794 894 797 894 797 918 773 918 86132 892 798 1768 770 918 774 916 778 913 803 889 804 888 1653 1739 800 889 804 888 804 888 804 888 86144 918 773 1769 771 915 777 915 777 915 778 914 778 914 1627 1765 774 914 777 915 777 915 778 914 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 975 746 946 717 1879 660 974 719 972 721 920 798 894 1648 1744 794 894 798 894 797 894 1644 918 85281 920 773 945 749 1793 769 917 775 916 777 915 777 915 1628 1765 774 915 778 914 778 914 1624 914 85282 943 772 919 773 1767 774 914 778 914 778 914 778 914 1627 1766 774 914 778 914 778 914 1624 914 85311 919 773 919 774 1766 773 915 778 914 778 914 778 914 1627 1766 774 915 778 914 778 914 1624 914 +# +# Model: Grundig AndroidTV +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 920 772 920 772 1771 768 920 771 920 772 920 771 948 748 948 743 948 1590 946 746 1795 1613 919 85291 892 799 893 799 1767 772 916 777 914 778 914 779 913 783 913 779 913 1625 913 780 1762 1623 912 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 872 800 873 797 1723 808 875 798 875 827 873 772 900 799 873 799 873 1614 873 800 1718 816 867 86386 844 828 844 828 1744 786 845 828 845 828 845 828 845 828 844 828 845 1643 844 828 1693 838 844 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 896 775 845 828 1746 785 845 828 846 827 848 826 845 1641 1693 838 844 828 845 828 845 828 845 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 957 716 1725 805 878 826 847 826 846 827 875 797 847 1641 1695 834 874 799 873 800 872 1617 870 85382 847 824 1695 835 873 800 871 803 869 804 868 806 867 1645 1691 841 842 831 842 831 842 1646 842 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 868 804 868 805 1717 812 870 804 896 777 869 803 870 804 869 1618 1744 790 867 805 866 807 866 86344 867 807 866 807 1716 816 868 806 867 805 867 806 868 805 869 1622 1713 841 843 804 867 806 869 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 925 747 1743 787 926 747 925 747 926 746 953 719 872 801 927 1562 1772 785 897 776 894 1594 867 85501 926 747 1771 785 897 776 894 779 867 806 867 807 866 807 866 1622 1713 818 866 807 866 1622 866 85508 926 748 1770 786 869 804 868 806 867 807 866 807 866 807 866 1623 1713 819 865 807 866 1623 866 85517 925 748 1770 786 896 777 868 806 867 807 866 807 866 807 866 1622 1714 818 866 807 866 1623 865 +# +# Model: GRUNDIG UNKNOWN +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 846 826 847 797 1723 837 846 826 847 826 847 826 846 826 846 826 846 1641 847 827 1717 1631 867 85430 845 827 845 827 1718 813 869 805 867 806 867 808 865 809 864 809 864 1624 864 832 1689 1635 863 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 926 751 1760 756 922 756 921 782 897 782 897 783 897 784 897 784 897 1624 897 784 1736 787 895 85521 921 780 1734 784 896 783 894 785 895 784 895 784 895 785 895 784 896 1625 895 785 1735 787 896 85546 894 783 1732 763 917 783 896 783 896 784 895 784 895 785 894 785 897 1624 897 784 1734 786 897 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 953 724 927 750 1764 755 924 755 924 758 922 782 898 782 899 1624 1737 786 898 784 897 784 898 85552 923 756 921 757 1759 783 898 782 898 782 898 783 897 783 897 1623 1737 785 897 784 897 784 897 85557 927 750 926 753 1762 782 898 782 898 759 921 782 898 783 898 1623 1737 785 898 784 898 783 898 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 952 725 1763 752 927 753 925 756 922 780 899 781 899 782 899 1623 1737 786 897 784 897 1626 895 84746 892 785 1731 787 894 785 894 785 895 786 895 789 891 786 895 1627 1732 789 894 788 893 1628 894 84705 929 748 1766 751 930 750 929 750 929 750 929 752 928 753 927 1593 1766 756 926 756 925 1597 924 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 896 782 895 784 1733 785 896 785 868 812 894 784 920 762 871 812 918 1605 893 787 1735 1629 892 84752 893 784 895 781 1735 762 919 783 895 786 897 783 896 785 896 786 895 1625 897 784 1738 1625 896 84727 916 784 896 781 1736 785 897 783 896 784 896 785 897 784 895 785 897 1624 897 783 1737 1627 897 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 921 753 1759 785 896 782 897 782 897 783 895 784 896 1623 1733 786 895 784 895 784 893 785 895 85568 893 783 1734 786 893 785 895 783 895 785 894 785 895 1622 1733 786 894 784 896 784 895 784 895 +# +# Model: GuestTek Marriot_Hotel +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 5349 102096 3672 530 1194 102545 5171 102367 969 658 1613 481 1499 103984 503 388 210 337 161 +# +name: Vol_up +type: parsed +protocol: NECext +address: 00 7F 00 00 +command: 48 B7 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 00 7F 00 00 +command: 44 BB 00 00 +# +name: Ch_next +type: parsed +protocol: NECext +address: 00 7F 00 00 +command: 0A F5 00 00 +# +name: Ch_prev +type: parsed +protocol: NECext +address: 00 7F 00 00 +command: 06 F9 00 00 +# +# Model: Haier L42C1180 +# +name: Mute +type: parsed +protocol: NECext +address: 00 7F 00 00 +command: 5A A5 00 00 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9021 4377 655 452 654 452 654 1567 654 453 653 453 653 453 652 454 651 455 651 1568 654 1569 653 455 651 1570 652 1570 652 1570 652 1571 651 1572 649 480 626 481 624 482 623 1599 623 483 623 484 622 484 622 484 622 1601 621 1601 621 1601 621 484 622 1601 621 1601 621 1601 621 1601 621 39912 8910 2137 622 95435 8933 2137 622 95434 8934 2137 622 95434 8934 2137 622 95434 8934 2137 622 95434 8933 2137 622 95434 8933 2138 621 95436 8932 2138 621 95435 8933 2138 621 95435 8933 2137 622 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8990 4407 626 479 627 479 627 1596 626 479 627 480 681 425 681 425 681 425 681 1541 680 1542 679 428 626 1596 626 1596 626 1596 626 1596 626 1596 626 480 626 1597 625 481 625 482 624 506 600 506 600 506 600 507 599 1624 622 483 623 1599 623 1599 623 1599 623 1600 622 1600 622 1600 622 39912 8909 2138 623 95460 8906 2140 623 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8990 4406 626 481 625 481 625 1595 627 481 625 481 653 453 654 452 654 452 654 1567 654 1568 654 453 653 1568 654 1569 653 1569 653 1569 653 1570 652 1594 627 1595 626 479 626 480 625 481 624 482 624 483 623 483 623 483 623 484 622 1600 622 1600 622 1600 622 1600 622 1600 622 1600 622 39913 8911 2137 622 95438 8934 2136 623 +# +# Model: Hisense ER22601A +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9020 4375 657 450 656 451 654 1566 656 451 655 451 653 453 626 480 653 452 655 1567 654 1568 654 454 651 1568 654 1568 654 1569 653 1570 651 1572 650 1595 626 479 626 480 625 1597 624 482 624 482 624 483 623 483 623 483 623 1599 623 1599 623 483 623 1599 623 1599 623 1599 623 1599 623 39900 8912 2136 623 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 976 723 1776 796 925 804 897 804 897 803 897 803 897 803 897 803 922 1610 919 783 1767 807 914 86103 921 778 1769 805 916 786 914 788 913 787 914 787 914 788 913 811 890 1617 914 787 1764 832 889 86082 920 778 1768 804 916 786 914 786 914 786 914 786 914 786 915 786 915 1616 915 786 1763 809 913 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 950 750 980 720 1800 770 926 774 926 774 926 775 925 1632 1775 796 922 779 920 782 919 782 919 86232 897 802 923 777 1772 801 918 782 919 783 917 783 918 1613 1769 802 918 783 917 783 918 783 917 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 979 721 1776 794 926 775 925 775 925 775 925 775 925 1606 1800 796 922 779 919 781 919 1612 919 85400 924 776 1772 800 919 781 919 782 918 781 919 782 919 1612 1770 801 919 782 918 782 919 1612 919 85390 923 776 1772 799 919 781 919 781 919 781 919 781 919 1612 1770 801 919 782 918 782 918 1613 918 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 979 720 977 724 1776 795 925 775 924 775 951 750 950 750 950 1582 1796 799 919 781 919 782 919 86138 949 752 946 777 1771 801 919 782 919 782 918 782 918 782 918 1612 1769 802 918 782 918 782 918 +# +# Model: Hisense K321UW +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 951 749 1832 741 978 721 927 774 926 776 924 776 924 801 899 1632 1773 798 920 782 918 1613 917 85257 898 802 1773 800 919 782 918 782 919 782 919 782 918 782 918 1613 1769 802 918 783 918 1614 917 85260 898 802 1772 800 919 782 919 782 919 782 919 782 918 782 919 1613 1769 802 918 782 918 1613 918 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8510 4237 528 1592 528 1592 528 526 529 526 529 526 529 526 529 526 529 527 528 1591 529 1591 529 1592 528 527 528 1590 530 526 529 526 529 525 528 22533 529 1590 529 1592 528 526 529 526 529 526 529 526 529 526 529 526 529 1592 528 1591 555 1564 556 500 555 1565 554 500 529 526 529 524 529 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8507 4232 528 1591 528 1590 529 527 528 527 527 526 528 527 528 526 529 525 530 526 529 1591 528 1591 528 1590 529 1591 528 528 527 527 527 525 528 22529 525 1592 527 1592 526 528 527 527 528 529 525 527 528 527 527 527 528 527 527 1592 527 1593 526 1592 527 1592 527 527 528 554 500 527 526 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8505 4231 528 1593 526 1595 524 525 529 526 529 526 528 525 529 527 527 526 528 1590 529 1590 529 1590 529 1590 529 1591 528 527 527 527 527 525 528 21460 528 1590 529 1590 529 525 529 526 528 526 528 526 528 526 528 527 527 1592 527 1592 527 1591 528 1591 528 1591 528 526 528 526 528 525 528 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8506 4232 528 1591 528 1591 528 526 528 526 528 528 526 526 528 527 527 526 528 526 528 526 528 1591 528 1592 527 1591 528 525 529 526 528 526 527 23593 528 1591 528 1592 527 526 528 526 528 526 528 526 529 527 527 528 526 525 529 527 527 1591 528 1591 528 1591 528 526 528 526 528 526 527 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8505 4231 528 1591 528 1591 527 527 527 526 528 526 552 503 527 528 526 526 528 1591 528 527 527 526 529 1592 527 1592 527 525 529 527 527 526 527 23590 527 1590 528 1590 528 525 529 526 528 526 528 526 528 526 528 526 528 1590 529 526 528 526 528 1590 529 1591 528 526 528 526 528 523 530 +# +# Model: Kendo CP20M36VT +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8505 4233 526 1591 528 1591 528 526 528 526 528 527 527 527 527 526 528 528 526 528 526 526 528 525 529 1591 528 1591 528 527 527 526 528 524 529 24651 528 1595 524 1591 527 526 528 528 526 526 528 526 528 528 526 527 527 526 528 526 528 527 527 1592 527 1591 527 527 527 528 526 525 552 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9121 4377 685 475 658 476 656 1610 656 479 654 482 651 483 651 483 651 483 651 1618 650 1618 650 506 627 1640 628 1641 627 1641 627 1640 628 1641 627 1641 627 1641 627 506 627 506 628 507 627 506 627 507 627 507 626 507 627 507 627 1641 626 1641 627 1641 627 1641 627 1641 627 1641 627 39937 9096 2169 651 +# +# Model: LG OLED48C37LA (LG_OLED C3 models) +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9097 4402 685 475 659 475 658 1609 657 477 656 480 653 480 654 480 653 481 653 1615 653 1614 654 481 653 1615 653 1615 653 1615 653 1615 653 1615 653 1615 653 481 652 481 653 1616 652 482 652 482 652 482 652 482 652 482 652 1616 652 1616 651 482 652 1617 651 1617 651 1640 628 1640 628 39937 9097 2167 652 +# +name: Mute +type: parsed +protocol: NECext +address: 83 7A 00 00 +command: 09 00 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 83 7A 00 00 +command: 02 40 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 83 7A 00 00 +command: 03 40 00 00 +# +name: Ch_prev +type: parsed +protocol: NECext +address: 83 7A 00 00 +command: 01 00 00 00 +# +# Model: Manta +# +name: Ch_next +type: parsed +protocol: NECext +address: 83 7A 00 00 +command: 00 00 00 00 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8073 3997 524 502 495 505 492 1508 498 503 494 1505 501 1500 495 1504 491 1510 496 3988 522 502 495 1505 501 501 496 504 493 1507 499 502 495 1505 501 501 496 18806 8072 3997 524 502 495 505 492 1507 499 502 495 1505 490 1509 497 1504 491 1510 496 3988 522 502 495 1505 501 500 497 503 494 1506 500 501 496 1504 491 510 498 18806 8072 3998 523 503 494 506 491 1509 497 504 493 1506 499 1501 494 1506 500 1502 493 3989 522 504 493 1507 499 502 495 505 492 1508 498 503 494 1506 499 502 495 18807 8072 3998 523 503 494 506 491 1509 497 504 493 1506 500 1501 494 1506 500 1502 493 3989 521 503 494 1506 500 502 495 505 492 1508 498 503 494 1506 500 502 495 18807 8072 3998 523 502 495 505 492 1508 498 503 494 1505 501 1500 495 1504 491 1510 496 3988 523 502 495 1505 501 501 496 503 494 1506 500 501 496 1504 491 510 498 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8069 3998 522 503 494 506 491 1509 496 505 492 1507 498 1501 494 1506 499 1502 493 3989 521 1503 492 1508 497 1503 492 508 500 1501 494 506 491 510 498 504 493 17810 8067 4003 517 508 500 501 496 1504 491 510 498 1502 493 1507 498 1501 494 1508 497 3984 526 1474 521 1504 501 1500 495 505 492 1509 496 505 492 508 500 502 495 17809 8069 4000 520 506 491 509 499 1501 494 507 501 1499 496 1503 492 1508 497 1504 491 3991 519 1480 525 1500 495 1505 500 500 497 1503 492 509 499 503 494 507 490 17809 8069 3999 521 505 492 508 500 1500 495 506 491 1508 497 1502 493 1507 498 1503 492 3990 520 1504 491 1509 496 1504 491 509 499 1501 494 507 501 501 496 505 492 17808 8070 3998 523 503 494 506 491 1509 496 504 493 1507 498 1501 494 1506 499 1502 493 3988 522 1502 493 1507 498 1502 493 507 501 1500 495 505 492 509 499 502 495 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8066 4002 519 507 501 500 497 1503 492 508 500 1500 495 1480 525 1475 520 1506 499 3983 517 508 500 1500 495 1481 524 501 496 1504 491 510 498 503 494 507 501 18803 8073 3997 524 503 494 506 491 1483 522 504 493 1506 499 1476 519 1482 523 1478 517 3989 521 504 493 1482 523 1478 517 508 500 1476 519 507 501 500 497 505 492 18809 8066 4003 517 508 500 501 496 1503 492 509 499 1501 494 1480 525 1475 520 1481 524 3983 516 509 499 1501 494 1482 523 502 495 1505 500 500 497 504 493 508 500 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8069 4000 520 480 517 508 500 1500 495 505 492 1508 497 1502 493 1506 499 1502 493 3989 521 1503 492 1509 496 503 494 1506 499 1501 494 506 491 510 498 504 493 17807 8072 3997 524 501 496 505 492 1508 497 502 495 1505 500 1499 496 1504 491 1510 495 3986 524 1500 495 1506 499 500 497 1503 492 1508 497 503 494 507 501 501 496 17804 8064 4004 517 509 499 501 496 1504 491 509 499 1500 495 1505 500 1499 496 1505 500 3980 520 1505 500 1500 495 505 492 1508 497 1502 493 508 500 501 496 505 492 17807 8072 3995 526 500 497 503 494 1506 499 501 496 1504 491 1508 497 1503 492 1509 496 3985 515 1509 496 1503 492 508 500 1500 495 1506 499 501 496 505 492 509 499 17803 8065 4003 518 508 500 501 496 1504 491 509 499 1502 493 1507 498 1502 493 1508 497 3985 525 1500 495 1505 500 500 497 1503 492 1508 497 504 493 508 500 501 496 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8064 4006 525 501 496 504 493 1507 498 502 495 1505 500 1499 496 1504 501 1500 495 3987 523 1501 494 1507 498 502 495 505 492 1508 497 1503 492 509 499 503 494 17808 8069 4000 520 505 492 508 500 1500 495 506 491 1508 497 1503 492 1508 497 1504 491 3991 519 1505 500 1501 494 507 501 500 497 1502 493 1508 497 503 494 508 500 17803 8064 4006 525 501 496 504 493 1507 498 503 494 1505 500 1500 495 1505 500 1500 495 3988 522 1502 493 1507 498 503 494 506 491 1508 497 1503 492 509 499 503 494 +# +# Model: NEC E425 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8068 3999 521 504 493 507 501 1498 497 504 493 1505 500 1475 520 1479 526 1500 495 3987 523 502 495 1505 500 501 496 504 493 1506 499 1501 494 507 501 500 497 18802 8072 3996 524 502 495 505 492 1507 498 503 494 1505 500 1475 520 1480 525 1476 519 3987 523 501 496 1504 491 510 498 502 495 1504 501 1475 520 505 492 509 498 18798 8065 4001 519 507 501 499 498 1502 493 507 501 1499 496 1504 501 1473 522 1504 501 3981 518 506 491 1509 496 505 492 508 499 1500 495 1505 500 500 497 505 492 18808 8065 4001 519 507 501 500 497 1503 492 508 499 1500 495 1505 500 1499 496 1506 499 3983 516 508 499 1501 494 507 501 500 497 1502 493 1508 497 504 493 508 500 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8953 4403 601 417 701 516 602 515 602 411 706 515 603 515 575 1635 603 514 628 1553 628 1609 600 1583 627 1606 598 1610 601 1608 600 495 624 1607 599 516 603 515 601 517 572 547 599 1608 599 518 601 516 598 545 573 1610 573 1637 572 1636 597 1612 599 518 600 1610 598 1610 599 1611 598 39250 8972 2171 599 94711 8976 2167 602 94731 8955 2168 602 94737 8927 2198 598 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3554 1678 495 403 468 1248 495 403 497 374 497 375 497 374 497 374 497 375 496 375 496 375 495 377 493 378 492 380 490 1254 489 383 488 383 489 383 488 383 488 383 488 383 489 383 488 383 489 383 488 1255 488 383 488 384 488 383 488 384 487 384 487 384 487 384 488 384 488 384 487 1256 487 384 488 384 487 1256 488 1256 488 384 487 384 487 384 488 1256 487 384 488 384 487 1257 487 1257 487 385 486 1257 487 +# +# Model: Panasonic N2QAYA_152 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3526 1678 495 403 468 1248 496 403 496 375 496 375 497 375 496 375 496 376 495 376 495 376 495 377 493 378 492 380 490 1254 488 384 488 383 488 384 488 384 487 384 487 384 487 384 488 384 487 384 488 1257 486 385 486 385 486 385 487 385 486 386 486 409 462 409 462 410 461 410 462 410 461 1282 462 409 462 1282 462 1282 461 410 462 410 461 410 461 410 462 1282 461 410 462 1282 461 1282 462 410 461 1282 462 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3519 1775 426 448 422 1332 418 455 425 449 421 459 421 452 418 456 424 450 420 459 421 452 418 456 424 450 420 460 420 1339 422 458 422 451 419 455 425 449 421 459 421 452 418 455 425 449 421 459 421 1339 422 457 423 451 419 454 426 448 422 458 422 451 419 454 426 448 422 1331 419 454 426 1327 423 450 420 1307 454 1299 451 449 421 453 427 1326 424 449 421 1333 417 456 424 1329 421 1304 446 454 426 1327 423 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3516 1747 444 456 424 1329 421 453 427 446 424 451 419 460 420 454 426 447 423 451 419 461 419 454 426 447 423 451 419 1334 427 448 422 458 422 451 419 455 425 450 420 459 421 453 417 456 424 450 420 1333 417 457 423 456 424 449 421 453 427 447 423 457 423 450 420 454 426 1328 422 451 419 456 424 455 425 448 422 1331 419 455 425 448 422 1332 418 455 425 449 421 459 421 452 418 1336 425 449 421 1332 418 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3482 1730 448 425 450 1296 444 429 446 427 448 424 451 422 453 420 445 428 447 425 450 423 452 421 444 429 446 426 449 1297 454 419 446 427 448 425 450 423 452 420 445 428 447 426 449 424 451 421 444 1303 448 425 450 422 453 420 445 428 447 425 450 423 452 421 444 429 446 427 448 424 451 422 453 419 446 428 447 1298 453 420 445 428 447 426 449 424 451 421 444 429 446 427 448 1298 453 420 445 1301 450 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3512 1700 478 395 480 1266 474 399 476 396 479 394 481 392 473 400 475 397 478 395 480 393 482 390 475 398 477 396 479 1267 473 399 476 397 478 395 480 392 473 400 475 398 477 396 479 394 481 391 474 1272 479 394 481 392 473 400 475 398 477 395 480 393 482 391 474 399 476 1269 482 391 474 399 476 397 478 395 480 1266 474 398 477 396 479 1267 473 399 476 397 478 394 481 392 473 1273 478 395 480 1266 474 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3596 1604 513 388 429 1282 459 442 428 442 428 442 428 442 428 442 428 441 429 441 429 442 428 442 428 443 426 445 449 1289 452 446 423 447 423 448 422 448 422 448 422 448 422 448 422 448 422 448 422 1319 422 448 422 448 422 448 422 448 422 448 422 448 422 448 423 448 422 448 422 448 422 448 422 448 422 448 422 1319 422 448 422 449 422 448 422 448 422 448 422 448 422 448 422 1319 422 448 422 1320 421 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3480 1715 457 441 429 1284 457 442 428 442 428 442 428 442 428 442 428 441 429 442 428 442 453 417 453 417 453 418 451 1289 451 421 449 447 423 447 423 447 423 447 423 448 422 448 422 448 423 447 423 1318 423 447 423 448 422 448 423 447 423 448 423 448 422 448 422 448 422 1319 422 448 422 448 422 448 423 448 422 1319 422 448 423 448 422 1319 422 448 422 448 422 448 422 448 422 1319 422 448 423 1319 422 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3537 1660 458 441 429 1311 430 442 428 442 428 442 428 442 428 442 428 442 428 442 428 442 428 442 453 417 453 417 453 1287 453 420 449 422 447 447 423 448 422 448 422 448 422 448 422 448 422 448 422 1319 422 448 422 447 423 448 422 448 422 448 422 448 422 448 422 448 423 448 422 1319 422 448 422 448 423 1319 422 1319 423 448 422 448 422 448 422 1319 422 448 422 448 422 1319 422 1319 422 448 422 1319 422 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3481 1715 457 441 429 1311 430 442 429 442 428 442 428 442 428 442 428 441 429 442 428 442 453 417 453 417 452 419 450 1289 451 422 447 447 423 447 423 447 423 448 422 448 422 448 422 448 422 448 422 1319 422 448 422 448 422 448 422 448 422 448 423 448 422 448 422 448 422 448 422 448 422 1319 422 448 422 1319 422 1319 422 448 422 448 422 448 422 448 422 1319 422 448 422 1319 422 1319 422 448 422 1319 422 +# +# Model: Panasonic TC-P50S2 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3505 1690 483 416 454 1258 483 416 454 416 454 417 428 442 428 442 428 441 455 416 454 416 454 416 454 417 452 419 450 1289 451 421 448 423 447 448 422 448 422 448 422 448 422 448 422 448 422 448 422 1319 422 448 422 448 422 448 422 448 423 448 422 448 423 448 422 448 422 1319 422 448 422 1319 422 448 422 1319 422 1319 422 448 422 448 423 1319 422 448 422 1319 422 448 422 1319 422 1320 421 449 421 1319 422 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 228 144285 3545 1690 497 411 495 1256 496 382 465 410 466 410 493 383 493 386 489 411 464 413 462 415 460 417 459 417 459 418 459 1295 458 418 459 418 459 418 458 418 458 418 459 418 458 418 459 418 459 418 459 1295 459 418 459 418 458 418 459 418 458 418 458 418 458 419 458 418 458 419 458 419 458 418 458 419 458 419 458 1296 458 418 458 418 458 419 457 419 458 419 457 419 458 419 458 1296 457 419 457 1296 458 +# +# Model: Panasonic Unknown_Full +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3404 1652 462 422 432 1230 457 427 437 420 434 424 440 417 436 420 434 424 440 417 436 421 433 424 440 417 436 421 432 1228 459 425 439 419 434 422 432 426 438 419 434 422 431 426 438 419 435 422 431 1230 457 426 438 420 433 423 431 426 438 420 433 423 430 427 437 420 434 1228 459 424 440 1221 466 418 435 1225 462 1226 461 422 432 426 438 1224 463 420 433 1228 459 399 465 1222 465 1223 464 420 433 1225 462 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2737 825 494 832 494 390 492 392 1352 1328 461 450 405 450 435 477 297 587 296 644 295 92395 2734 829 491 836 490 394 491 419 1286 1395 296 587 378 1474 239 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 182 7827 172 2332 177 2328 181 2323 176 2330 179 1309 175 1331 174 2331 178 1328 177 2328 181 1307 177 2327 182 1325 180 1326 179 1309 176 1331 174 1332 173 2333 176 2310 178 1328 177 2328 181 1325 180 2306 182 1325 180 2325 174 8340 183 7825 175 2330 179 2326 173 2333 176 2310 178 1328 177 1329 176 2329 180 1308 176 2329 180 1326 179 2326 173 1334 182 1306 179 1328 177 1329 176 1312 183 2322 177 2329 180 1326 179 2325 174 1315 180 2326 173 1333 183 2323 176 8339 183 7824 175 2330 179 2307 181 2324 175 2331 178 1328 177 1330 175 2311 177 1329 176 2329 180 1326 179 2327 182 1305 179 1328 177 1328 177 1311 173 1334 182 2323 176 2330 179 1326 571 1916 180 1327 178 2325 587 920 575 1930 579 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 179 7828 182 2323 176 2328 181 2323 176 2329 180 1308 176 1330 175 2329 180 1326 179 2307 181 2323 176 2329 180 2325 174 1332 173 1315 180 1327 179 1328 177 2327 182 2322 177 1311 173 2332 177 1329 176 1330 175 1312 183 1324 181 8332 180 7826 174 2331 178 2326 173 2313 176 2330 179 1327 178 1328 177 2327 182 1306 179 2326 183 2322 177 2328 181 2323 176 1312 183 1324 181 1325 180 1325 180 2307 181 2323 176 1331 174 2330 179 1327 178 1310 175 1331 174 1332 173 8323 179 7845 176 2311 177 2327 182 2322 177 2328 181 1325 180 1308 177 2328 181 1325 180 2325 174 2330 179 2326 173 2314 174 1332 173 1332 173 1333 183 1306 178 2326 183 2322 177 1329 176 2328 181 1307 177 1329 176 1330 175 1313 182 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 183 7824 176 2329 180 2324 175 2329 180 2324 175 1314 181 1325 180 2324 175 1331 174 2331 178 2307 181 2324 175 1331 174 1331 174 1314 181 1326 179 1326 179 2325 174 2332 177 1310 174 2330 179 1327 178 1328 177 1310 174 2330 179 8334 178 7827 173 2332 177 2327 182 2323 176 2310 178 1328 177 1328 177 2327 182 1306 179 2326 183 2322 177 2327 182 1324 181 1307 177 1329 176 1330 176 1331 174 2311 177 2328 181 1325 180 2324 175 1332 173 1313 182 1325 180 2324 175 8339 173 1383 2522 3925 179 2325 576 1909 590 1915 594 1910 589 918 588 919 576 1911 175 1332 173 2330 592 1912 587 1918 581 907 588 918 598 908 587 920 575 913 592 1914 182 2320 592 914 581 1927 180 1307 178 1327 592 915 580 1925 574 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 176 7830 180 2324 175 2329 180 2324 175 2329 180 1308 176 1329 176 2328 181 1325 180 2305 183 2321 178 1329 177 2327 182 1324 181 1306 178 1328 177 1329 176 2327 182 2304 174 1332 173 2332 177 1328 177 1310 174 2330 179 1327 178 8333 179 7826 174 2330 179 2325 174 2313 175 2329 180 1326 179 1326 179 2325 174 1315 180 2324 175 2329 180 1326 179 2325 174 1314 181 1325 180 1326 179 1308 177 2328 181 2323 176 1330 175 2329 180 1308 176 1330 175 2328 181 1325 180 8314 177 7845 176 2310 178 2327 182 2322 177 2327 182 1323 182 1306 179 2326 173 1333 183 2322 177 2327 182 1305 179 2326 173 1333 183 1323 182 1305 179 1327 178 2326 173 2331 178 1327 178 2308 180 1326 179 1327 178 2325 174 1315 180 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 182 7824 176 2328 181 2323 176 2328 181 2324 175 1312 183 1323 182 2322 177 1330 175 2309 179 2325 174 1332 173 1333 183 1305 179 1327 178 1328 177 1328 177 2308 180 262 177 1885 175 295 175 861 174 2330 179 99 313 911 573 915 590 1916 180 64 349 1910 176 265 174 7896 177 3081 835 3912 182 2322 177 207 179 1942 180 2304 174 268 181 1881 179 263 176 889 177 264 175 886 583 1925 182 271 178 855 180 240 178 1907 174 2331 178 1327 178 1309 176 1329 590 916 589 919 173 306 175 833 181 317 174 1832 175 2329 180 1325 180 309 182 1833 174 1313 182 1325 180 289 181 1853 175 2329 180 8313 178 7845 176 2309 179 2325 174 2331 178 2326 173 1333 183 1304 180 2324 175 1332 173 2330 179 2325 174 1314 181 1325 180 1326 179 1327 178 1308 177 1330 175 2329 180 2324 175 1312 183 2322 177 1329 176 1329 176 2329 180 2304 174 8339 173 351 3575 3902 594 1911 588 1916 593 1911 588 1916 583 904 591 916 589 1915 594 911 584 1920 579 1907 592 915 590 915 591 916 579 908 597 909 596 909 586 1919 580 1907 179 1326 592 1912 597 908 587 901 594 1911 588 1916 593 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9047 4385 682 474 682 1578 708 476 679 1581 706 477 679 1582 705 1582 705 1582 678 1583 679 1607 679 1582 678 478 679 478 678 477 679 1582 705 1582 679 1583 679 1608 704 1582 705 478 678 1582 705 478 678 478 678 478 679 477 679 478 679 478 678 1582 705 478 678 1583 704 1582 705 1582 679 39574 9073 4387 679 478 678 1583 679 503 677 1584 705 478 678 1582 705 1582 705 1582 705 1582 705 1582 705 1582 678 479 677 479 678 479 677 1583 679 1608 704 1582 705 1582 705 1582 705 478 678 1583 704 478 678 478 678 1582 680 478 703 453 704 453 703 1557 703 480 676 1584 704 1583 704 478 678 +# +name: Ch_next +type: parsed +protocol: Samsung32 +address: 05 00 00 00 +command: 12 00 00 00 +# +# Model: Samsung BN59-01081A +# +name: Ch_prev +type: parsed +protocol: Samsung32 +address: 05 00 00 00 +command: 10 00 00 00 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4499 4472 566 1662 565 1664 563 1665 562 565 538 564 539 562 541 560 543 558 545 1683 544 1658 569 1686 541 559 544 557 536 565 538 563 540 561 542 559 544 1684 543 558 545 556 537 564 539 562 541 560 543 558 545 1684 543 558 545 1683 544 1684 543 1660 567 1688 539 1689 538 1664 563 565 538 563 540 561 542 559 544 42973 4495 4472 566 1662 565 1663 564 1664 563 564 539 562 541 560 543 558 545 556 537 1691 536 1691 536 1666 572 555 538 564 539 561 542 559 544 557 536 565 538 1689 538 563 540 560 543 558 545 555 538 563 540 561 542 1686 541 559 544 1684 543 1684 543 1658 569 1685 542 1686 541 1660 567 559 544 557 536 565 538 563 540 42959 4499 4466 562 1666 572 1656 571 1656 571 556 537 564 539 562 541 559 544 556 537 1691 536 1690 537 1664 563 564 539 562 541 560 543 557 536 565 538 563 540 1688 539 561 542 559 544 556 537 564 539 562 541 560 543 1684 543 558 545 1682 545 1683 544 1657 570 1684 543 1659 568 1659 568 559 544 557 536 565 538 563 540 42955 4503 4463 565 1663 564 1663 564 1664 563 563 540 561 542 558 545 556 537 564 539 1688 539 1688 539 1662 565 562 541 559 544 557 536 565 538 563 540 560 543 1685 542 559 544 556 537 564 539 562 541 559 544 557 536 1692 535 565 538 1690 537 1690 537 1664 563 1691 536 1666 572 1656 571 556 537 564 539 562 541 559 544 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4507 4464 564 1690 537 1691 536 1666 572 555 538 538 565 562 541 559 544 557 536 1693 545 1656 571 1657 570 557 536 565 538 563 540 561 542 558 545 1683 544 1657 570 1684 543 558 545 555 538 563 540 561 542 559 544 557 536 565 538 563 540 1688 539 1662 565 1663 564 1663 564 1664 563 564 539 536 567 560 543 558 545 42962 4496 4470 568 1686 541 1660 567 1661 566 560 543 558 545 556 537 564 539 561 542 1686 541 1660 567 1687 540 534 569 558 545 555 538 563 540 561 542 1686 541 1686 541 1686 541 533 570 557 536 565 538 563 540 560 543 558 545 555 538 563 540 1661 566 1687 540 1661 566 1661 566 1662 565 561 542 533 570 557 536 564 539 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4506 4465 563 1692 546 1658 569 1659 568 559 544 557 536 565 538 563 540 561 542 1687 540 1662 565 1689 538 563 540 561 542 560 543 558 545 556 537 1665 562 1693 545 530 563 1692 546 555 538 564 539 562 541 560 543 558 545 556 537 1665 562 539 564 1690 537 1691 536 1692 535 1693 545 556 537 539 564 563 540 561 542 42974 4505 4464 564 1690 537 1665 562 1667 571 530 563 565 538 563 540 561 542 559 544 1684 543 1659 568 1661 566 561 542 559 544 557 536 565 538 563 540 1663 564 1690 537 563 540 1662 565 559 558 545 556 537 564 539 562 541 1688 539 561 542 1687 540 1688 539 1688 539 1663 564 563 540 561 542 559 544 557 536 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4498 4471 567 1661 566 1662 565 1664 563 564 539 563 540 561 542 559 544 557 536 1693 545 1684 543 1659 568 559 544 557 536 566 537 564 539 562 541 560 543 1686 541 560 543 558 545 1684 543 558 545 556 537 564 539 1690 537 564 539 1689 538 1690 537 564 539 1689 538 1665 562 1666 572 556 537 564 539 563 540 560 543 42964 4504 4464 564 1690 537 1665 562 1666 572 555 538 564 539 562 541 560 543 558 545 1683 544 1684 543 1659 568 558 545 556 537 565 538 563 540 560 543 558 545 1683 544 556 537 565 538 1690 537 564 539 561 542 560 543 1685 542 558 545 1683 544 1657 570 557 536 1692 546 1683 544 1684 543 557 536 566 537 563 540 561 542 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4506 4464 564 1691 536 1692 546 1656 571 556 537 564 539 562 541 560 543 558 545 1683 544 1684 543 1685 542 558 545 556 537 565 538 563 540 561 542 558 545 556 537 564 539 562 541 1687 540 561 542 558 545 556 537 1691 536 1665 562 1692 546 1656 571 556 537 1691 536 1692 546 1683 544 557 536 565 538 563 540 560 543 42966 4502 4466 562 1693 545 1683 544 1684 543 558 545 556 537 564 539 561 542 559 544 1684 543 1684 543 1658 569 558 545 530 563 564 539 562 541 560 543 558 535 566 537 564 539 562 541 1687 540 560 543 558 545 555 538 1691 536 1665 562 1693 545 1657 570 557 536 1666 572 1683 544 1658 569 557 546 529 564 563 540 561 542 +# +# Model: Samsung LE37S71B +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4497 4474 564 1690 537 1691 536 1666 572 556 537 564 539 562 541 560 543 558 545 1683 544 1683 544 1684 543 532 571 556 537 564 539 562 541 560 543 1659 568 1686 541 1661 566 1662 565 562 541 560 543 558 535 565 538 563 540 561 542 558 545 556 537 1665 562 1666 572 1656 571 1684 543 557 546 555 538 564 539 562 541 42966 4502 4466 562 1692 535 1693 545 1657 570 556 537 565 538 562 541 560 543 543 1656 571 1656 571 1657 570 557 536 565 538 563 540 560 543 558 545 1683 544 1683 544 1657 570 1684 543 531 562 565 538 563 540 560 543 558 545 556 537 564 539 561 542 1660 567 1686 541 1687 540 1662 565 562 541 533 570 557 536 565 538 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4567 4475 732 1555 703 1608 705 1608 705 478 676 460 669 507 651 506 649 508 621 1640 672 1616 673 1639 674 508 648 508 648 508 647 485 644 511 647 508 648 1639 674 508 649 508 647 485 645 511 647 508 648 509 647 1639 674 509 647 1613 673 1641 673 1640 673 1640 672 1617 671 1640 673 48544 4566 4505 648 1639 674 1639 674 1639 647 510 648 508 648 509 648 508 648 508 648 1639 647 1642 673 1639 674 508 648 509 648 508 647 485 645 511 647 509 647 1640 673 509 647 509 646 486 643 511 647 509 647 509 647 1640 673 509 647 1615 672 1640 673 1640 673 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4583 4485 687 1600 690 1623 716 1596 690 493 660 470 634 521 662 495 659 497 658 1629 684 1630 631 1657 682 500 656 500 656 500 656 500 656 475 653 1633 682 1631 682 1631 682 500 629 502 630 526 656 500 656 500 656 500 656 500 657 500 630 1632 682 1631 682 1631 682 1631 654 1633 682 48536 4553 4518 656 1632 682 1631 682 1631 682 500 630 502 629 526 656 500 656 501 656 1631 682 1631 631 1657 656 526 655 501 655 501 655 501 655 501 629 1634 680 1632 681 1632 681 501 629 502 629 527 654 501 655 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4551 4491 683 1630 658 1628 685 1628 685 500 654 499 631 525 657 499 656 500 656 1632 681 1632 652 1635 681 501 655 501 655 501 655 501 655 501 628 1634 680 1632 681 501 655 1632 680 479 626 528 628 528 654 502 654 502 654 502 655 1632 654 504 627 1659 680 1632 681 1633 654 1634 679 48515 4596 4498 654 1634 653 1633 654 1633 628 529 653 502 654 502 654 502 654 502 654 1633 653 1635 679 1633 680 503 653 503 653 479 651 504 627 528 654 1633 680 1633 680 503 627 1634 679 503 653 503 653 503 653 503 653 503 627 504 627 1660 679 503 653 1634 679 1634 652 1636 678 1634 679 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1221 1189 435 588 436 890 433 2388 435 590 434 1489 434 1789 434 1190 434 1188 436 2689 435 1488 435 1190 434 86920 327 929 326 377 327 652 328 +# +# Model: Samsung Royal_Caribbean +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1195 1216 407 616 408 917 406 2414 410 617 406 1518 405 1815 409 1215 434 590 408 2717 406 1516 408 2417 407 86346 375 881 375 326 378 602 377 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1253 1157 464 560 465 858 460 2364 460 563 462 1462 463 1761 467 1156 465 1159 462 2661 467 1456 469 1155 466 86886 331 925 330 373 328 652 331 +# +# Model: Samsung TV_1 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1224 1186 467 556 437 887 441 2382 463 560 433 1490 466 1757 461 1163 458 566 438 2686 463 1460 465 2359 434 86319 301 953 302 402 330 649 334 +# +name: Vol_dn +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 0b 00 00 00 +# +name: Mute +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 0f 00 00 00 +# +# Model: Sencor 25801 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9040 4407 659 463 659 1579 661 461 685 437 658 463 658 463 658 464 657 470 656 1585 654 491 629 1611 628 1613 626 1614 625 1615 625 1615 625 502 625 1615 625 497 625 496 625 1614 625 1615 625 497 625 497 624 503 624 496 625 1615 624 1615 624 497 625 496 625 1615 624 1615 624 1614 624 41051 9036 2175 625 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 264 1848 264 792 264 792 264 792 264 792 264 792 264 1848 264 1848 264 792 264 1848 264 792 264 792 264 792 264 1848 264 792 264 43560 264 1848 264 792 264 792 264 792 264 792 264 1848 264 792 264 792 264 1848 264 792 264 1848 264 1848 264 1848 264 792 264 1848 264 43560 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 264 1848 264 792 264 792 264 792 264 792 264 1848 264 792 264 792 264 792 264 1848 264 792 264 792 264 792 264 1848 264 792 264 43560 264 1848 264 792 264 792 264 792 264 792 264 792 264 1848 264 1848 264 1848 264 792 264 1848 264 1848 264 1848 264 792 264 1848 264 43560 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 264 1848 264 792 264 792 264 792 264 792 264 792 264 1848 264 792 264 792 264 1848 264 792 264 792 264 792 264 1848 264 792 264 43560 264 1848 264 792 264 792 264 792 264 792 264 1848 264 792 264 1848 264 1848 264 792 264 1848 264 1848 264 1848 264 792 264 1848 264 43560 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 264 1848 264 792 264 792 264 792 264 792 264 792 264 792 264 1848 264 792 264 1848 264 792 264 792 264 792 264 1848 264 792 264 43560 264 1848 264 792 264 792 264 792 264 792 264 1848 264 1848 264 792 264 1848 264 792 264 1848 264 1848 264 1848 264 792 264 1848 264 43560 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 264 1848 264 792 264 792 264 792 264 792 264 1848 264 792 264 1848 264 792 264 1848 264 792 264 792 264 792 264 1848 264 792 264 43560 264 1848 264 792 264 792 264 792 264 792 264 792 264 1848 264 792 264 1848 264 792 264 1848 264 1848 264 1848 264 792 264 1848 264 43560 +# +# Model: Sharp Aquos_32BG3E +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 264 1848 264 792 264 792 264 792 264 792 264 1848 264 1848 264 1848 264 792 264 1848 264 792 264 792 264 792 264 1848 264 792 264 43560 264 1848 264 792 264 792 264 792 264 792 264 792 264 792 264 792 264 1848 264 792 264 1848 264 1848 264 1848 264 792 264 1848 264 43560 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3381 1656 439 401 438 1239 439 401 438 1240 439 401 438 1239 440 401 438 1239 440 400 439 1238 440 401 438 1239 440 1240 438 426 438 1240 439 400 439 1240 439 1240 438 1240 438 1240 438 401 438 401 438 402 437 1242 436 402 437 1242 437 402 437 403 436 1242 437 402 437 403 436 403 436 403 436 1242 437 1242 437 403 436 1242 437 403 436 403 436 403 436 1242 437 403 436 403 436 403 436 1243 436 403 436 1242 437 1242 437 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3378 1656 440 400 439 1239 440 400 439 1239 439 400 439 1239 440 399 440 1238 440 400 439 1239 521 371 412 1215 464 1215 464 399 440 1239 439 399 440 1239 439 1240 438 1240 438 1241 438 401 438 401 438 402 437 1242 437 402 437 1242 437 402 437 402 437 1242 437 402 437 402 437 402 437 1242 437 1242 437 1242 437 402 437 1242 437 402 437 402 437 402 437 1242 437 402 437 402 437 402 437 402 437 402 437 1242 437 1242 437 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3374 1661 436 403 436 1243 436 404 435 1243 436 404 435 1243 436 403 435 1242 464 376 463 1215 464 378 461 1216 463 1219 460 402 437 1242 436 403 436 1243 435 1244 435 1244 434 1245 433 405 434 406 433 406 433 1246 433 406 433 1246 433 406 433 406 433 1246 433 406 433 406 433 406 433 406 433 406 433 1246 433 406 433 1246 433 406 433 406 433 406 433 1246 433 406 433 406 433 406 433 1246 433 1246 433 1246 433 1246 433 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3516 1521 438 401 438 1240 439 401 438 1240 439 401 438 1239 440 400 439 1238 466 375 465 1213 465 375 522 1156 522 1158 520 372 466 1184 494 372 412 1240 439 1240 438 1241 438 1241 437 402 437 402 437 402 437 1242 437 402 437 1242 437 403 436 402 437 1243 436 403 436 403 436 403 436 1243 436 403 436 1243 436 403 436 1243 436 403 436 403 436 403 436 1243 436 403 436 403 436 403 436 403 436 1243 436 1243 436 1243 436 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3382 1654 467 374 440 1238 465 375 440 1238 441 398 441 1238 466 374 466 1211 442 424 415 1238 441 424 415 1240 465 1238 441 398 441 1238 441 398 441 1238 440 1238 440 1239 439 1240 439 400 439 400 439 401 438 1241 438 401 438 1241 438 401 438 401 438 1241 438 401 438 401 438 401 438 1241 438 401 439 401 438 401 438 1241 438 401 438 401 438 401 438 1241 438 401 438 401 438 401 438 401 438 1241 438 401 438 1241 438 +# +# Model: Sharp g0684cesa_NES_TV +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3361 1649 443 423 416 1237 442 398 441 1235 444 398 441 1237 442 398 441 1237 442 397 442 1236 443 397 442 1236 443 1237 442 399 440 1236 443 398 441 1263 416 1263 472 1207 471 1207 470 371 414 423 416 423 416 1263 416 423 416 1263 416 423 416 423 416 1262 417 422 417 422 417 422 417 422 417 1262 416 422 417 422 417 1262 416 423 441 398 441 398 441 1238 441 398 441 398 441 399 440 1239 440 399 440 399 440 1238 441 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 278 1811 277 788 246 794 250 764 280 786 248 792 252 1813 275 1815 273 791 253 1812 276 789 255 785 249 791 253 1812 276 789 255 45322 280 1809 279 786 248 766 278 788 246 794 250 1815 273 792 252 788 246 1819 280 785 249 1817 271 1819 280 1810 278 787 247 1818 281 43217 274 1818 270 794 250 764 280 786 248 792 252 788 256 1809 279 1811 277 788 246 1819 280 785 249 766 278 762 272 1819 280 785 248 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 278 1812 276 762 282 758 276 765 279 761 273 1818 281 1809 279 1811 277 762 282 1809 279 760 274 766 278 762 282 1809 279 760 274 44279 276 1813 275 763 281 759 275 766 278 762 272 768 276 764 280 760 274 1817 271 768 276 1815 273 1817 271 1819 280 759 275 1816 272 44276 279 1812 276 763 281 758 276 765 279 761 273 1818 281 1810 278 1811 277 762 272 1819 279 760 274 766 278 762 282 1809 279 760 274 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 272 1817 271 794 250 790 254 786 248 792 252 762 272 794 250 1815 273 792 252 1813 275 790 254 785 249 766 278 1813 275 789 255 46372 273 1817 271 794 250 763 281 785 248 792 252 1813 275 1814 274 791 253 1812 276 789 255 1810 278 1812 276 1813 275 790 254 1811 277 42170 277 1814 274 791 253 787 247 793 251 763 281 759 275 791 253 1812 276 789 255 1810 278 787 247 793 251 789 255 1810 278 787 247 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 275 1814 274 791 253 787 247 793 251 789 255 1810 278 787 247 1818 281 785 249 1816 272 793 251 789 255 785 249 1816 272 766 278 45325 274 1815 273 792 252 762 272 794 250 790 254 786 247 1818 270 794 250 1815 273 792 252 1813 275 1815 273 1816 272 793 251 1814 274 43224 277 1814 274 764 280 786 248 792 252 788 246 1820 279 786 247 1817 271 768 276 1815 273 792 252 761 273 794 250 1815 273 791 253 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 272 1817 271 794 250 790 254 786 248 792 252 1813 275 790 254 759 275 792 252 1813 275 789 255 785 248 792 252 1813 275 789 255 46372 273 1817 271 793 251 763 281 759 275 791 253 787 247 1818 281 1810 278 1812 276 789 255 1809 279 1811 277 1813 275 790 254 1811 277 42169 277 1815 273 792 252 787 247 794 250 789 255 1810 278 787 247 794 250 789 255 1810 278 761 273 793 251 789 255 1810 278 787 247 +# +# Model: Sharp LC-RC1-16 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 273 1816 272 767 277 789 255 785 249 791 253 787 246 1818 281 785 248 765 279 1812 276 789 255 759 275 791 253 1812 276 789 255 46372 281 1808 280 785 249 791 253 787 247 793 251 1814 274 791 253 1812 276 1814 274 791 253 1812 276 1814 274 1815 273 792 252 1813 275 42172 272 1819 280 785 249 765 279 761 273 768 276 764 280 1811 277 788 246 768 276 1815 273 792 252 788 246 794 250 1815 273 791 253 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 352 1747 353 694 354 694 353 694 354 694 354 693 354 1747 354 1745 355 693 355 1746 354 693 355 691 357 691 356 1745 355 689 356 46388 358 1740 359 689 358 688 360 689 358 689 359 1741 358 688 359 689 359 1741 358 691 356 1743 356 1743 356 1742 357 690 357 1741 356 44286 261 1839 260 786 262 786 262 785 263 785 263 786 262 1838 262 1838 262 786 262 1839 261 786 262 784 264 787 261 1837 263 783 262 46491 261 1839 261 786 262 786 262 786 261 786 262 1839 261 786 262 786 262 1839 261 786 262 1838 262 1838 262 1838 262 786 262 1835 262 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 308 1788 312 735 313 734 313 735 313 736 312 735 313 736 312 1788 312 735 313 1786 314 735 313 735 313 734 314 1787 313 731 314 47491 314 1786 314 734 314 734 314 734 314 732 316 1786 315 1784 316 733 315 1786 315 732 316 1785 315 1787 314 1785 315 733 315 1781 317 43284 314 1784 316 731 317 730 318 732 316 732 316 732 316 731 317 1783 317 732 316 1784 316 733 315 731 317 731 317 1784 317 730 315 47500 313 1785 315 733 315 733 315 733 315 734 314 1787 313 1786 315 733 315 1787 313 733 315 1787 313 1786 314 1787 313 734 314 1783 314 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 357 1739 361 688 360 690 357 688 360 691 356 1741 359 689 359 1741 358 690 358 1742 357 691 357 690 357 693 355 1744 356 689 356 46399 355 1743 357 691 357 691 357 691 357 692 355 692 356 1744 356 692 356 1744 356 692 356 1744 355 1745 355 1745 263 785 263 1835 263 44390 261 1839 262 786 262 787 261 787 261 786 262 1839 261 787 261 1840 261 786 262 1839 262 786 262 785 263 785 263 1839 261 784 261 46497 262 1839 261 786 262 786 262 787 261 786 262 786 262 1838 262 786 262 1840 260 787 261 1839 261 1840 260 1840 260 787 261 1835 263 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 260 1838 262 787 261 786 262 787 261 786 261 1838 262 1838 262 1838 262 786 262 1839 261 786 262 786 262 786 262 1839 261 784 261 45433 261 1839 261 785 263 785 263 785 263 785 263 786 262 786 262 785 263 1838 262 786 262 1839 261 1837 263 1838 262 786 262 1835 263 45436 356 1744 356 691 356 691 356 692 356 691 356 1743 357 1744 356 1745 355 691 356 1745 354 692 356 693 354 691 356 1745 355 691 353 45343 359 1742 358 688 360 688 359 689 359 687 361 688 360 689 359 688 360 1741 359 688 360 1742 358 1739 361 1741 359 689 359 1739 359 45337 286 1813 287 761 287 761 287 761 287 760 288 1813 287 1813 287 1813 287 760 288 1813 287 760 288 760 288 760 288 1812 288 757 288 45413 287 1814 286 761 287 761 287 759 289 760 288 760 288 761 287 760 288 1813 287 762 286 1813 287 1813 287 1813 361 685 288 1810 288 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 356 1743 358 689 359 690 358 689 359 689 359 1741 359 688 360 688 360 688 360 1739 362 687 361 687 361 686 362 1739 361 684 361 47444 287 1812 288 760 288 759 289 760 288 759 288 760 288 1813 287 1812 288 1812 312 736 288 1812 288 1812 288 1813 287 760 288 1810 287 43309 286 1812 288 761 310 736 288 759 289 762 286 1812 312 737 311 736 312 736 312 1790 311 737 311 736 312 736 312 1789 311 734 312 47501 313 1786 314 733 315 734 314 733 315 734 314 733 315 1785 315 1785 315 1786 314 733 315 1785 315 1786 314 1786 314 731 317 1782 316 43279 339 1760 317 731 339 709 316 730 318 733 315 1783 317 732 316 731 317 731 317 1784 316 732 316 731 317 731 317 1785 315 729 316 +# +# Model: Sharp Roku_TV +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 287 1812 288 760 288 761 287 761 287 761 287 760 288 1814 286 760 288 761 287 1813 287 760 288 760 288 760 288 1813 287 757 312 47498 340 1759 341 707 341 709 315 731 340 708 340 1760 340 707 341 1759 318 1783 317 730 318 1782 318 1783 317 1784 316 731 317 1782 316 43284 314 1787 314 736 312 734 314 734 314 734 314 735 313 1787 314 735 313 734 314 1787 313 735 313 734 314 733 315 1787 314 732 313 47500 285 1813 361 685 363 687 361 687 361 686 362 1739 360 687 361 1740 359 1740 360 689 358 1741 359 1743 356 1746 353 690 357 1741 356 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 195 1833 300 766 280 760 275 790 276 737 309 731 304 1801 301 1804 309 731 304 1801 270 795 282 758 277 762 273 1832 270 769 246 45851 326 1780 302 739 307 785 282 732 303 736 310 1795 307 732 303 763 303 1775 307 733 334 1798 273 1832 270 1810 251 814 273 1780 281 43762 302 1804 309 758 277 737 330 762 284 730 305 734 301 1803 310 1796 306 733 302 1829 273 767 279 734 301 791 275 1804 278 762 253 45870 307 1798 304 763 272 767 279 787 279 760 275 1829 284 730 305 734 301 1804 309 757 278 1827 275 1804 278 1828 274 765 270 1835 278 43740 303 1776 306 787 279 760 275 765 281 759 307 758 277 1775 307 1799 303 736 299 1832 281 759 276 763 304 736 299 1832 281 733 302 45820 306 1800 302 764 282 758 277 788 278 762 284 1821 281 732 303 736 310 1796 307 733 302 1829 273 1806 276 1830 272 767 268 1837 245 43772 302 1778 304 789 277 762 284 756 279 786 249 765 301 1777 336 1770 301 764 282 1824 278 761 274 765 301 738 308 1824 278 761 274 +# +# Model: Sharp TV2 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 254 1721 360 681 354 738 308 706 329 711 355 1774 307 1772 361 1744 327 687 359 1772 299 742 335 705 330 736 279 1825 298 742 283 44773 384 1721 360 707 308 707 359 733 302 711 335 705 361 704 331 708 338 1766 336 704 331 1773 329 1776 306 1773 360 681 323 1782 331 44726 411 1722 328 686 360 733 302 711 335 705 361 1742 329 1803 330 1749 332 708 327 1777 335 705 330 710 325 741 274 1830 303 737 278 44778 359 1747 355 712 303 711 355 711 335 705 330 709 337 703 363 703 332 1770 332 709 337 1767 335 1771 300 1752 360 733 302 1776 326 44731 355 1751 330 711 355 737 309 705 330 710 336 1793 309 1771 331 1774 307 706 360 1771 300 740 326 714 332 735 280 1798 325 741 274 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 277 1806 274 775 281 776 279 770 275 774 281 768 277 1814 277 1806 274 775 280 1803 277 780 276 773 282 766 279 1831 249 781 274 45962 281 1803 277 771 274 783 273 802 253 770 275 1834 257 801 255 768 277 1807 273 775 280 1811 280 1804 276 1806 274 774 282 1811 280 43887 275 1809 282 767 278 779 276 799 256 766 279 771 274 1843 248 1810 281 767 278 1806 274 782 274 776 279 796 249 1807 273 784 282 45962 279 1804 276 772 273 784 282 768 277 798 247 1836 255 802 253 796 249 1808 283 766 279 1813 278 1805 275 1808 272 776 279 1813 278 43890 282 1801 279 769 276 781 274 775 280 769 276 773 283 1834 257 1801 279 769 276 1808 272 784 282 767 278 772 273 1810 281 776 279 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 282 1801 280 769 276 781 275 774 282 768 277 1805 276 781 275 775 281 769 276 1832 249 809 247 776 280 770 275 1834 247 784 282 47004 273 1811 280 768 277 780 276 773 283 767 278 771 274 1816 275 1809 272 1811 280 768 277 1815 276 1807 274 1809 282 767 278 1813 278 42841 284 1799 282 768 277 780 276 774 282 767 278 1805 276 781 275 774 282 768 277 1806 275 782 274 775 281 769 276 1807 274 783 283 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 273 1810 281 768 277 780 276 799 257 767 278 797 248 1816 275 774 282 768 277 1806 275 808 248 801 255 795 250 1807 274 809 247 46989 278 1805 276 799 246 784 282 767 278 798 247 1835 256 775 281 1803 278 1806 275 773 283 1809 272 1811 280 1803 278 771 274 1817 274 42868 278 1806 275 799 257 775 281 768 277 798 247 776 280 1811 280 770 275 773 283 1801 280 777 279 771 274 801 255 1802 279 778 278 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 282 1801 280 769 276 781 275 775 281 768 277 772 273 784 282 1801 280 770 275 1807 274 784 282 767 278 771 274 1809 282 775 281 47005 282 1801 280 770 275 782 274 776 280 769 276 1807 274 1817 274 775 280 1803 278 771 274 1817 274 1809 282 1801 280 770 275 1815 276 42841 273 1811 280 769 276 781 275 774 282 768 277 772 273 783 273 1811 280 794 251 1806 275 782 274 776 280 769 276 1808 273 783 283 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 277 1805 276 799 246 785 281 768 277 798 247 1810 281 775 281 1804 277 771 274 1810 281 801 255 795 250 772 273 1811 280 776 280 45957 274 1809 272 777 279 778 278 772 273 776 280 769 276 1815 276 799 246 1811 280 769 276 1815 276 1807 274 1809 282 767 278 1813 278 43890 280 1803 278 797 248 783 273 776 280 796 249 1834 247 784 282 1802 279 796 249 1808 273 783 283 793 252 770 275 1808 273 784 282 +# +# Model: Silver LE410004 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 281 1803 278 771 274 782 274 775 281 769 276 1807 274 1817 274 1835 256 766 280 1804 277 780 276 773 283 767 278 1831 250 780 276 44910 276 1835 256 766 280 777 279 771 275 774 282 767 278 779 277 773 283 1800 281 768 277 1814 277 1806 275 1808 283 766 279 1811 280 44937 280 1803 278 771 274 783 283 766 279 770 275 1808 273 1819 272 1811 280 768 277 1807 274 782 274 776 280 769 276 1833 248 784 282 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8958 4449 510 4475 515 4444 515 2213 508 4477 513 2215 516 2212 509 2219 512 2217 514 2214 517 2211 540 2214 517 2211 510 4449 510 2218 513 4472 507 2220 511 30572 8960 2218 513 87698 8966 2211 510 87701 8963 2214 568 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8956 4451 508 2220 511 2217 514 4470 510 4449 510 2218 544 2211 510 2218 513 2215 516 2212 509 2220 511 2217 514 2214 517 2211 510 2245 517 4441 508 2220 511 35049 8961 2215 516 87696 8959 2217 514 87698 8956 2220 511 87701 8964 2213 508 +# +name: Ch_prev +type: parsed +protocol: SIRC +address: 01 00 00 00 +command: 10 00 00 00 +# +name: Ch_next +type: parsed +protocol: SIRC +address: 01 00 00 00 +command: 11 00 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 1C 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 4B 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 4F 00 00 00 +# +name: Ch_next +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 09 00 00 00 +# +name: Ch_prev +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 05 00 00 00 +# +# Model: Strong TVD221_B1825 +# +name: Mute +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 08 00 00 00 +# +name: Power +type: raw +frequency: 36700 +duty_cycle: 0.330000 +data: 3488 3488 872 2616 872 872 872 872 872 2616 872 872 872 2616 872 872 872 872 872 872 872 872 872 872 872 2616 872 872 872 2616 872 2616 872 872 872 2616 872 872 872 2616 872 2616 872 2616 872 2616 872 2616 872 872 872 34008 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3488 3488 872 2616 872 872 872 872 872 2616 872 872 872 2616 872 872 872 872 872 872 872 872 872 2616 872 2616 872 872 872 2616 872 2616 872 872 872 2616 872 872 872 2616 872 2616 872 2616 872 2616 872 872 872 872 872 34008 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3488 3488 872 2616 872 872 872 872 872 2616 872 872 872 2616 872 2616 872 872 872 872 872 872 872 2616 872 2616 872 872 872 2616 872 2616 872 872 872 2616 872 872 872 872 872 2616 872 2616 872 2616 872 872 872 872 872 34008 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3488 3488 872 2616 872 872 872 872 872 2616 872 872 872 2616 872 872 872 872 872 872 872 872 872 2616 872 872 872 872 872 2616 872 2616 872 872 872 2616 872 872 872 2616 872 2616 872 2616 872 2616 872 872 872 2616 872 34008 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3488 3488 872 2616 872 872 872 872 872 2616 872 872 872 2616 872 872 872 872 872 872 872 2616 872 872 872 872 872 872 872 2616 872 2616 872 872 872 2616 872 872 872 2616 872 2616 872 2616 872 872 872 2616 872 2616 872 34008 +# +# Model: TCL 32S327 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3488 3488 872 2616 872 872 872 872 872 2616 872 872 872 2616 872 2616 872 2616 872 872 872 872 872 2616 872 2616 872 872 872 2616 872 2616 872 872 872 2616 872 872 872 872 872 872 872 2616 872 2616 872 872 872 872 872 34008 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4012 3982 514 1984 519 1979 514 1984 519 1979 514 983 519 980 512 1988 516 982 520 1979 514 1984 519 1978 515 983 519 980 511 987 515 983 519 980 511 1988 516 1982 511 987 515 1983 521 978 514 985 517 981 521 1978 515 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 171 91301 168 17617 175 4907 167 15077 177 55723 170 4910 174 7448 174 15071 173 4908 176 17609 172 7450 172 7451 171 68432 169 7454 168 7454 168 4913 171 7451 171 4911 173 4908 176 7446 176 7446 176 50643 176 4905 169 4912 172 7450 172 7450 172 7451 171 4911 173 7448 174 4908 176 4905 169 7452 170 7453 169 50649 169 4912 173 4909 175 7447 175 7448 174 7448 174 4908 176 7446 176 4906 168 4913 171 7450 172 7451 171 50647 171 4911 173 4908 176 7445 177 7445 177 7446 176 4906 168 7454 168 4913 171 4910 174 7448 174 7449 173 50645 173 9990 169 7453 169 7454 168 7455 177 4905 169 7452 170 4912 172 4909 175 7447 175 7447 175 50644 174 4908 176 4905 169 7453 169 7454 168 7454 178 4904 170 7452 170 4912 172 4909 175 7447 175 7448 174 55726 177 4905 169 7453 169 7452 170 7453 169 4914 170 7451 171 4910 174 4907 177 7446 176 7446 176 50642 176 4906 168 4913 171 7452 170 7452 170 7453 169 4912 172 7450 172 4910 174 4907 177 7445 177 7446 176 50642 176 9987 172 7450 171 15074 170 4911 173 7450 172 4909 175 4906 168 7455 177 7446 176 50641 176 9988 171 7451 171 7451 171 7452 170 4912 172 7450 172 4909 175 4906 168 7454 178 7444 177 50641 167 4914 170 4911 174 7449 173 7449 173 7449 173 4909 175 7447 175 4907 177 4904 170 15075 169 50650 168 4913 171 4910 174 7448 174 7448 174 7448 174 4908 176 7447 175 4907 177 4903 171 7452 170 7452 170 50648 170 4912 172 4909 175 7446 176 7447 175 7448 174 4907 177 7446 176 4906 168 4912 172 7450 172 7451 171 50648 170 4912 172 4908 176 7446 176 7446 176 7447 175 4906 168 7454 178 4904 170 4911 173 15072 172 50646 173 4908 176 4906 168 7454 168 7455 177 7444 168 4915 169 7453 169 4913 171 4910 174 7448 174 7448 174 50644 174 4908 176 4904 170 7453 169 7453 169 7454 178 4904 170 40 198 7213 170 4910 174 4907 177 7446 176 7446 176 50643 175 4905 169 4913 171 7451 171 7452 170 7452 170 4911 173 7449 173 4909 175 4905 169 7454 168 7454 168 50650 178 4904 170 4911 173 7449 173 7450 172 7451 171 4910 174 7448 174 4907 177 4905 169 7453 169 7453 169 50649 169 4913 172 4910 174 15071 173 7449 173 4908 176 7447 175 4906 168 4913 171 7451 171 7451 171 50648 170 4911 173 4909 175 7446 176 7447 175 7448 174 4908 176 7446 176 4905 169 4913 171 15074 170 50648 170 4912 172 20154 175 7448 174 4907 177 7445 177 4904 170 4912 172 7450 172 7450 172 50647 170 4911 173 4908 176 7447 174 7447 174 7448 174 4908 176 7446 175 4906 168 4913 171 7451 171 7452 170 50649 168 4912 172 4910 174 7447 175 7448 174 7449 172 4909 175 7447 174 4907 177 4904 170 7452 170 7453 169 50649 169 4913 171 4910 174 7449 173 7449 173 7450 172 4909 175 7447 175 4906 168 4914 170 7452 170 7453 169 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 170 86221 170 7452 169 7453 168 12536 170 7452 169 43026 168 15077 177 7445 176 20150 168 15076 178 4904 170 7452 170 73516 168 7454 168 12536 171 7452 170 12534 172 7450 171 7451 171 43025 170 7452 170 15075 169 15077 177 4904 170 7452 170 7452 170 12535 172 7450 172 81138 178 12526 170 27779 172 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 169 12535 174 88758 177 7445 168 4913 172 7450 173 4908 177 7445 168 48108 171 4910 175 4907 168 7454 169 7454 169 7453 170 7454 169 7452 171 4911 174 7448 175 4907 168 7454 169 +# +# Model: Telefunken d32f660x5cwi +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 173 7448 175 7445 178 7443 170 7451 172 7449 174 7447 176 7445 168 4912 173 7447 176 7446 177 4903 172 43015 177 7443 170 7451 172 7448 175 7445 178 7444 169 7452 171 7449 174 4907 168 7452 171 7450 173 4907 168 43018 175 7447 176 7444 169 7453 170 7450 173 7448 175 7446 177 399 174 6870 169 4911 174 7447 176 7445 168 4912 173 43013 169 7451 172 7451 172 7448 175 7445 168 7453 170 7451 172 7449 174 4906 169 7452 171 7450 173 4907 168 43019 174 7447 176 7445 178 7443 170 7450 173 7448 175 7446 177 7444 169 4910 175 7447 176 7444 169 4913 172 43012 170 7452 171 7450 173 7448 175 7445 168 7453 170 7450 173 7449 174 4907 168 7452 171 7450 173 4908 177 43010 171 7448 175 7446 177 7444 169 7451 172 7448 175 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 328 605 321 283 643 290 313 589 316 287 639 596 642 589 316 285 318 285 641 591 637 294 309 587 328 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 331 601 314 289 647 285 308 595 320 282 644 591 647 584 321 282 644 587 318 285 641 290 313 583 332 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 330 632 294 281 645 288 315 585 320 284 642 593 645 585 320 284 642 589 649 583 644 586 329 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 333 600 315 288 638 294 309 594 321 281 645 591 636 595 643 589 638 592 313 290 646 585 330 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 334 628 287 289 647 285 308 593 322 307 619 589 649 582 323 280 646 586 641 589 316 287 639 89967 331 602 313 290 646 286 307 595 320 283 643 591 647 584 321 282 644 588 639 591 314 288 638 +# +# Model: Thomson 40FS3003 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 332 601 314 290 646 286 307 594 321 282 644 590 648 582 323 281 645 586 641 290 313 583 644 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9219 4484 662 469 661 469 661 1627 660 471 658 474 656 499 631 499 631 499 631 1657 630 1657 631 500 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 500 630 1657 630 500 631 500 630 500 631 500 630 1657 630 1658 630 1657 631 500 630 1657 631 1658 630 1658 630 1658 630 40107 9106 2202 631 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9218 4484 636 495 660 469 661 1627 660 471 658 472 658 474 656 475 655 474 656 1632 655 1632 656 474 657 1632 656 1631 657 1632 656 1631 656 1632 656 474 656 1632 655 475 656 474 657 474 656 474 656 474 656 474 656 1632 655 474 656 1632 656 1632 656 1632 656 1632 656 1632 656 1632 656 40103 9107 2177 655 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9245 4429 689 467 662 468 661 1626 660 471 658 473 657 474 656 474 656 474 656 1631 657 1631 657 474 656 1631 656 1632 656 1631 657 1631 657 1631 656 1632 656 1631 657 474 656 474 656 474 657 474 656 474 656 474 657 474 656 474 656 1631 656 1632 656 1632 656 1632 656 1632 656 1631 656 40082 9109 2175 656 +# +# Model: Vizio D43-C1 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9219 4485 636 495 660 469 661 1626 661 471 658 473 657 474 656 499 631 500 630 1657 630 1657 631 500 630 1657 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 1657 631 500 630 500 630 500 630 500 631 500 630 1657 631 1657 631 500 630 1657 631 1658 630 1657 631 1658 630 39868 9106 2178 655 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9016 4408 603 512 602 512 629 1599 686 428 630 483 630 484 629 485 628 492 627 1604 625 1605 624 491 623 1630 599 1631 598 1631 598 1631 598 1636 599 515 599 515 599 515 599 1631 599 515 599 515 599 515 599 521 599 1631 599 1631 599 1631 598 515 599 1631 598 1631 598 1631 598 1632 598 39999 9016 2166 626 95735 9012 2168 625 95735 9013 2167 626 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 988 605 587 1176 588 589 586 882 587 1178 585 588 588 589 587 1470 587 1175 589 588 587 590 586 13118 986 608 587 1177 587 588 587 882 587 1178 586 588 587 589 587 1470 587 1177 587 590 585 588 588 13117 987 609 586 1177 587 590 585 882 587 1177 587 589 586 588 588 1472 585 1176 588 588 587 588 587 13118 986 608 587 1177 586 589 587 881 588 1177 587 588 587 589 587 1470 587 1177 587 589 586 588 588 13116 988 609 586 1178 586 589 586 883 586 1177 587 589 586 590 586 1471 586 1178 585 588 587 588 588 13117 987 609 586 1177 587 589 587 883 586 1177 586 589 587 589 586 1472 585 1176 588 589 587 589 587 13116 988 610 585 1178 586 588 588 882 587 1176 588 590 586 588 587 1471 586 1177 586 589 587 589 586 +# +# Model: Zenith SC3492Z +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 990 603 589 1175 589 587 588 882 587 1175 588 588 588 589 586 1470 587 1471 587 588 588 881 588 12528 988 609 586 1177 587 589 586 882 587 1177 586 588 587 589 587 1470 587 1471 587 588 588 881 588 12527 989 607 588 1175 589 588 588 881 588 1175 588 588 588 587 589 1470 587 1470 588 589 587 881 588 12528 988 607 588 1175 589 588 587 882 587 1178 586 587 588 588 588 1472 586 1470 588 588 587 881 588 12529 987 608 587 1175 589 587 589 882 587 1175 589 589 587 587 589 1469 588 1470 588 587 589 881 588 12528 988 607 588 1175 589 590 585 883 586 1176 587 587 589 588 588 1471 586 1470 588 587 589 883 586 12527 989 607 588 1176 588 588 588 880 589 1176 588 588 588 589 586 1469 588 1469 589 588 587 881 588 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 611 386 612 3984 612 4984 612 387 611 3985 612 387 611 3986 611 4985 611 387 611 3986 611 4985 611 387 611 3986 610 4987 609 4985 611 389 609 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 595 403 595 4002 594 5001 595 404 594 4002 594 405 593 4003 594 5001 595 5001 595 405 593 4003 594 405 593 4004 592 5004 592 406 592 4004 593 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 596 401 597 4000 596 5000 596 402 596 4001 596 402 596 4002 595 5000 596 5000 596 403 595 4002 595 402 596 4003 594 5002 594 5000 596 404 594 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 484 514 485 4112 485 5111 485 514 485 4112 484 5110 486 513 486 4111 485 5110 486 514 485 4112 484 513 486 4112 484 5112 484 5113 483 513 486 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 591 405 593 4005 591 5005 591 407 591 4006 591 408 590 4006 591 5006 590 5004 592 406 591 4005 592 5005 591 407 591 4006 591 407 591 4007 590 +# +# Model: Zenith tv +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 598 400 598 3999 597 4999 596 401 597 4000 597 5000 596 402 596 3999 598 4999 597 401 597 4000 597 4998 598 402 596 4000 597 402 596 4000 597 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 561 442 562 4055 591 5032 592 413 591 4026 593 411 593 4026 593 5030 618 387 617 4001 592 5032 591 440 564 4028 591 5033 590 5034 589 440 563 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 591 411 593 4025 593 5030 593 411 593 4025 593 411 593 4025 618 5005 619 5003 593 439 564 4027 592 439 564 4029 590 5033 590 439 564 4055 563 123130 617 387 618 3999 593 5031 592 439 564 4027 592 439 564 4029 590 5034 589 5059 563 440 563 4056 563 442 561 4058 561 5063 560 443 560 4059 560 +# +name: Ch_next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 591 412 592 4026 593 5030 593 411 593 4025 594 411 617 4001 618 5005 619 5004 592 439 565 4028 590 5032 591 439 564 4055 564 440 563 4056 563 +# +name: Ch_prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 591 412 592 4026 592 5029 594 411 593 4025 593 5030 593 411 617 4001 619 5003 617 415 565 4027 592 5032 591 439 564 4030 589 439 564 4055 564 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 591 413 591 4027 592 5030 593 411 593 4026 593 412 592 4025 618 5005 620 5004 592 439 564 4028 591 439 564 4029 590 5033 590 5035 588 440 563 122125 617 387 619 4000 592 5032 591 439 564 4028 591 439 565 4030 589 5034 589 5059 564 441 562 4057 562 442 561 4058 561 5063 560 5063 560 444 560 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 590 412 592 4026 593 5030 593 412 592 4025 594 5029 594 412 616 4002 618 5003 593 439 564 4027 592 439 564 4029 590 5033 590 5035 588 440 563 From 8059959624ee366ab6d4fdf6aa246809ea373d3e Mon Sep 17 00:00:00 2001 From: David Coles Date: Tue, 11 Feb 2025 08:01:12 -0800 Subject: [PATCH 06/14] Ensure that `furi_record_create` is passed a non-NULL data pointer (#4078) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Ensure that `furi_record_create` is passed a non-NULL data pointer It's currently possible to use `furi_record_create` to create and initialize a `FuriRecordData` pointing to NULL. This means its potentially possible for `furi_record_open` to return a NULL pointer which besides not being particularly useful means the Rust wrapper for `Record` can't assume that the returned record is always a non-NULL value. If by chance this is the intended behaviour, then we can just have the Rust wrapper do a `furi_check` itself, but it seems like it would be better to eliminate this potential corner-case at the source. * Furi: update furi_record_create documentation Co-authored-by: あく --- furi/core/record.c | 1 + furi/core/record.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/furi/core/record.c b/furi/core/record.c index fa384369a..17c95aa9b 100644 --- a/furi/core/record.c +++ b/furi/core/record.c @@ -80,6 +80,7 @@ bool furi_record_exists(const char* name) { void furi_record_create(const char* name, void* data) { furi_check(furi_record); furi_check(name); + furi_check(data); furi_record_lock(); diff --git a/furi/core/record.h b/furi/core/record.h index a269484f0..1fb20ed6f 100644 --- a/furi/core/record.h +++ b/furi/core/record.h @@ -27,7 +27,7 @@ bool furi_record_exists(const char* name); /** Create record * * @param name record name - * @param data data pointer + * @param data data pointer (not NULL) * @note Thread safe. Create and destroy must be executed from the same * thread. */ From 00f287e297e8c782942b0d69bf477adddfc0a8da Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Thu, 13 Feb 2025 03:04:24 +0900 Subject: [PATCH 07/14] [FL-2754, FL-3945] EM4305 support (#4069) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial EM4305 write support * Support for writing EM4100 data to EM4305 blank tags * F18 API version bump * Satisfy pvs * Lib: cleanup em4305 code * Mask size fix * Electra * Fix leftovers from a previous implementation * Viking * Gallagher * LFRFID: cleanup em4305 Co-authored-by: あく --- lib/lfrfid/lfrfid_worker_modes.c | 112 +++++++++------- lib/lfrfid/protocols/lfrfid_protocols.h | 6 + lib/lfrfid/protocols/protocol_electra.c | 18 +++ lib/lfrfid/protocols/protocol_em4100.c | 26 ++++ lib/lfrfid/protocols/protocol_gallagher.c | 14 ++ lib/lfrfid/protocols/protocol_viking.c | 13 ++ lib/lfrfid/tools/em4305.c | 152 ++++++++++++++++++++++ lib/lfrfid/tools/em4305.h | 61 +++++++++ targets/f18/api_symbols.csv | 2 +- targets/f7/api_symbols.csv | 3 +- 10 files changed, 360 insertions(+), 47 deletions(-) create mode 100644 lib/lfrfid/tools/em4305.c create mode 100644 lib/lfrfid/tools/em4305.h diff --git a/lib/lfrfid/lfrfid_worker_modes.c b/lib/lfrfid/lfrfid_worker_modes.c index aec19e374..d3bcda042 100644 --- a/lib/lfrfid/lfrfid_worker_modes.c +++ b/lib/lfrfid/lfrfid_worker_modes.c @@ -499,9 +499,6 @@ static void lfrfid_worker_mode_emulate_process(LFRFIDWorker* worker) { static void lfrfid_worker_mode_write_process(LFRFIDWorker* worker) { LFRFIDProtocol protocol = worker->protocol; LFRFIDWriteRequest* request = malloc(sizeof(LFRFIDWriteRequest)); - request->write_type = LFRFIDWriteTypeT5577; - - bool can_be_written = protocol_dict_get_write_data(worker->protocols, protocol, request); uint32_t write_start_time = furi_get_tick(); bool too_long = false; @@ -510,63 +507,88 @@ static void lfrfid_worker_mode_write_process(LFRFIDWorker* worker) { size_t data_size = protocol_dict_get_data_size(worker->protocols, protocol); uint8_t* verify_data = malloc(data_size); uint8_t* read_data = malloc(data_size); + protocol_dict_get_data(worker->protocols, protocol, verify_data, data_size); - if(can_be_written) { - while(!lfrfid_worker_check_for_stop(worker)) { - FURI_LOG_D(TAG, "Data write"); - t5577_write(&request->t5577); + while(!lfrfid_worker_check_for_stop(worker)) { + FURI_LOG_D(TAG, "Data write"); + uint16_t skips = 0; + for(size_t i = 0; i < LFRFIDWriteTypeMax; i++) { + memset(request, 0, sizeof(LFRFIDWriteRequest)); + LFRFIDWriteType write_type = i; + request->write_type = write_type; - ProtocolId read_result = PROTOCOL_NO; - LFRFIDWorkerReadState state = lfrfid_worker_read_internal( - worker, - protocol_dict_get_features(worker->protocols, protocol), - LFRFID_WORKER_WRITE_VERIFY_TIME_MS, - &read_result); + protocol_dict_set_data(worker->protocols, protocol, verify_data, data_size); - if(state == LFRFIDWorkerReadOK) { - bool read_success = false; + bool can_be_written = + protocol_dict_get_write_data(worker->protocols, protocol, request); - if(read_result == protocol) { - protocol_dict_get_data(worker->protocols, protocol, read_data, data_size); - - if(memcmp(read_data, verify_data, data_size) == 0) { - read_success = true; - } - } - - if(read_success) { + if(!can_be_written) { + skips++; + if(skips == LFRFIDWriteTypeMax) { if(worker->write_cb) { - worker->write_cb(LFRFIDWorkerWriteOK, worker->cb_ctx); + worker->write_cb(LFRFIDWorkerWriteProtocolCannotBeWritten, worker->cb_ctx); } break; - } else { - unsuccessful_reads++; + } + continue; + } - if(unsuccessful_reads == LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS) { - if(worker->write_cb) { - worker->write_cb(LFRFIDWorkerWriteFobCannotBeWritten, worker->cb_ctx); - } + memset(read_data, 0, data_size); + + if(request->write_type == LFRFIDWriteTypeT5577) { + t5577_write(&request->t5577); + } else if(request->write_type == LFRFIDWriteTypeEM4305) { + em4305_write(&request->em4305); + } else { + furi_crash("Unknown write type"); + } + } + ProtocolId read_result = PROTOCOL_NO; + LFRFIDWorkerReadState state = lfrfid_worker_read_internal( + worker, + protocol_dict_get_features(worker->protocols, protocol), + LFRFID_WORKER_WRITE_VERIFY_TIME_MS, + &read_result); + + if(state == LFRFIDWorkerReadOK) { + bool read_success = false; + + if(read_result == protocol) { + protocol_dict_get_data(worker->protocols, protocol, read_data, data_size); + + if(memcmp(read_data, verify_data, data_size) == 0) { + read_success = true; + } + } + + if(read_success) { + if(worker->write_cb) { + worker->write_cb(LFRFIDWorkerWriteOK, worker->cb_ctx); + } + break; + } else { + unsuccessful_reads++; + + if(unsuccessful_reads == LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS) { + if(worker->write_cb) { + worker->write_cb(LFRFIDWorkerWriteFobCannotBeWritten, worker->cb_ctx); } } - } else if(state == LFRFIDWorkerReadExit) { - break; } + } else if(state == LFRFIDWorkerReadExit) { + break; + } - if(!too_long && - (furi_get_tick() - write_start_time) > LFRFID_WORKER_WRITE_TOO_LONG_TIME_MS) { - too_long = true; - if(worker->write_cb) { - worker->write_cb(LFRFIDWorkerWriteTooLongToWrite, worker->cb_ctx); - } + if(!too_long && + (furi_get_tick() - write_start_time) > LFRFID_WORKER_WRITE_TOO_LONG_TIME_MS) { + too_long = true; + if(worker->write_cb) { + worker->write_cb(LFRFIDWorkerWriteTooLongToWrite, worker->cb_ctx); } + } - lfrfid_worker_delay(worker, LFRFID_WORKER_WRITE_DROP_TIME_MS); - } - } else { - if(worker->write_cb) { - worker->write_cb(LFRFIDWorkerWriteProtocolCannotBeWritten, worker->cb_ctx); - } + lfrfid_worker_delay(worker, LFRFID_WORKER_WRITE_DROP_TIME_MS); } free(request); diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index e9c61616e..37b7f06cd 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -1,6 +1,7 @@ #pragma once #include #include "../tools/t5577.h" +#include "../tools/em4305.h" typedef enum { LFRFIDFeatureASK = 1 << 0, /** ASK Demodulation */ @@ -31,6 +32,7 @@ typedef enum { LFRFIDProtocolNexwatch, LFRFIDProtocolSecurakey, LFRFIDProtocolGProxII, + LFRFIDProtocolMax, } LFRFIDProtocol; @@ -38,11 +40,15 @@ extern const ProtocolBase* lfrfid_protocols[]; typedef enum { LFRFIDWriteTypeT5577, + LFRFIDWriteTypeEM4305, + + LFRFIDWriteTypeMax, } LFRFIDWriteType; typedef struct { LFRFIDWriteType write_type; union { LFRFIDT5577 t5577; + LFRFIDEM4305 em4305; }; } LFRFIDWriteRequest; diff --git a/lib/lfrfid/protocols/protocol_electra.c b/lib/lfrfid/protocols/protocol_electra.c index 014c83d1f..b4e17763f 100644 --- a/lib/lfrfid/protocols/protocol_electra.c +++ b/lib/lfrfid/protocols/protocol_electra.c @@ -407,6 +407,24 @@ bool protocol_electra_write_data(ProtocolElectra* protocol, void* data) { request->t5577.blocks_to_write = 5; result = true; } + if(request->write_type == LFRFIDWriteTypeEM4305) { + request->em4305.word[4] = + (EM4x05_MODULATION_MANCHESTER | EM4x05_SET_BITRATE(64) | (8 << EM4x05_MAXBLOCK_SHIFT)); + uint64_t encoded_data_reversed = 0; + uint64_t encoded_epilogue_reversed = 0; + for(uint8_t i = 0; i < 64; i++) { + encoded_data_reversed = (encoded_data_reversed << 1) | + ((protocol->encoded_base_data >> i) & 1); + encoded_epilogue_reversed = (encoded_epilogue_reversed << 1) | + ((protocol->encoded_epilogue >> i) & 1); + } + request->em4305.word[5] = encoded_data_reversed & 0xFFFFFFFF; + request->em4305.word[6] = encoded_data_reversed >> 32; + request->em4305.word[7] = encoded_epilogue_reversed & 0xFFFFFFFF; + request->em4305.word[8] = encoded_epilogue_reversed >> 32; + request->em4305.mask = 0x01F0; + result = true; + } return result; } diff --git a/lib/lfrfid/protocols/protocol_em4100.c b/lib/lfrfid/protocols/protocol_em4100.c index 8851a5369..83340895c 100644 --- a/lib/lfrfid/protocols/protocol_em4100.c +++ b/lib/lfrfid/protocols/protocol_em4100.c @@ -69,6 +69,19 @@ uint32_t protocol_em4100_get_t5577_bitrate(ProtocolEM4100* proto) { } } +uint32_t protocol_em4100_get_em4305_bitrate(ProtocolEM4100* proto) { + switch(proto->clock_per_bit) { + case 64: + return EM4x05_SET_BITRATE(64); + case 32: + return EM4x05_SET_BITRATE(32); + case 16: + return EM4x05_SET_BITRATE(16); + default: + return EM4x05_SET_BITRATE(64); + } +} + uint16_t protocol_em4100_get_short_time_low(ProtocolEM4100* proto) { return EM_READ_SHORT_TIME_BASE / protocol_em4100_get_time_divisor(proto) - EM_READ_JITTER_TIME_BASE / protocol_em4100_get_time_divisor(proto); @@ -339,6 +352,19 @@ bool protocol_em4100_write_data(ProtocolEM4100* protocol, void* data) { request->t5577.block[2] = protocol->encoded_data; request->t5577.blocks_to_write = 3; result = true; + } else if(request->write_type == LFRFIDWriteTypeEM4305) { + request->em4305.word[4] = + (EM4x05_MODULATION_MANCHESTER | protocol_em4100_get_em4305_bitrate(protocol) | + (6 << EM4x05_MAXBLOCK_SHIFT)); + uint64_t encoded_data_reversed = 0; + for(uint8_t i = 0; i < 64; i++) { + encoded_data_reversed = (encoded_data_reversed << 1) | + ((protocol->encoded_data >> i) & 1); + } + request->em4305.word[5] = encoded_data_reversed; + request->em4305.word[6] = encoded_data_reversed >> 32; + request->em4305.mask = 0x70; + result = true; } return result; } diff --git a/lib/lfrfid/protocols/protocol_gallagher.c b/lib/lfrfid/protocols/protocol_gallagher.c index 9ae0cf80a..bbed99706 100644 --- a/lib/lfrfid/protocols/protocol_gallagher.c +++ b/lib/lfrfid/protocols/protocol_gallagher.c @@ -264,6 +264,20 @@ bool protocol_gallagher_write_data(ProtocolGallagher* protocol, void* data) { request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); request->t5577.blocks_to_write = 4; result = true; + } else if(request->write_type == LFRFIDWriteTypeEM4305) { + request->em4305.word[4] = + (EM4x05_MODULATION_MANCHESTER | EM4x05_SET_BITRATE(32) | (7 << EM4x05_MAXBLOCK_SHIFT)); + uint32_t encoded_data_reversed[3] = {0}; + for(uint8_t i = 0; i < (32 * 3); i++) { + encoded_data_reversed[i / 32] = + (encoded_data_reversed[i / 32] << 1) | + (bit_lib_get_bit(protocol->encoded_data, ((32 * 3) - i)) & 1); + } + request->em4305.word[5] = encoded_data_reversed[2]; + request->em4305.word[6] = encoded_data_reversed[1]; + request->em4305.word[7] = encoded_data_reversed[0]; + request->em4305.mask = 0xF0; + result = true; } return result; } diff --git a/lib/lfrfid/protocols/protocol_viking.c b/lib/lfrfid/protocols/protocol_viking.c index 78499a415..7e9009fde 100644 --- a/lib/lfrfid/protocols/protocol_viking.c +++ b/lib/lfrfid/protocols/protocol_viking.c @@ -171,6 +171,19 @@ bool protocol_viking_write_data(ProtocolViking* protocol, void* data) { request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); request->t5577.blocks_to_write = 3; result = true; + } else if(request->write_type == LFRFIDWriteTypeEM4305) { + request->em4305.word[4] = + (EM4x05_MODULATION_MANCHESTER | EM4x05_SET_BITRATE(32) | (6 << EM4x05_MAXBLOCK_SHIFT)); + uint32_t encoded_data_reversed[2] = {0}; + for(uint8_t i = 0; i < 64; i++) { + encoded_data_reversed[i / 32] = + (encoded_data_reversed[i / 32] << 1) | + (bit_lib_get_bit(protocol->encoded_data, (63 - i)) & 1); + } + request->em4305.word[5] = encoded_data_reversed[1]; + request->em4305.word[6] = encoded_data_reversed[0]; + request->em4305.mask = 0x70; + result = true; } return result; } diff --git a/lib/lfrfid/tools/em4305.c b/lib/lfrfid/tools/em4305.c new file mode 100644 index 000000000..3b072d38d --- /dev/null +++ b/lib/lfrfid/tools/em4305.c @@ -0,0 +1,152 @@ +#include "em4305.h" +#include +#include + +#define TAG "EM4305" + +#define EM4305_TIMING_1 (32) +#define EM4305_TIMING_0_OFF (23) +#define EM4305_TIMING_0_ON (18) + +#define EM4305_FIELD_STOP_OFF_CYCLES (55) +#define EM4305_FIELD_STOP_ON_CYCLES (18) + +#define EM4305_TIMING_POWER_CHECK (1480) +#define EM4305_TIMING_EEPROM_WRITE (9340) + +static bool em4305_line_parity(uint8_t data) { + uint8_t parity = 0; + for(uint8_t i = 0; i < 8; i++) { + parity ^= (data >> i) & 1; + } + return parity; +} + +static uint64_t em4305_prepare_data(uint32_t data) { + uint8_t i, j; + uint64_t data_with_parity = 0; + + // 4 lines of 8 bits of data + // line even parity at bits 8 17 26 35 + // column even parity at bits 36-43 + // bit 44 is always 0 + // final table is 5 lines of 9 bits + + // line parity + for(i = 0; i < 4; i++) { + for(j = 0; j < 8; j++) { + data_with_parity = (data_with_parity << 1) | ((data >> (i * 8 + j)) & 1); + } + data_with_parity = (data_with_parity << 1) | (uint64_t)em4305_line_parity(data >> (i * 8)); + } + + // column parity + for(i = 0; i < 8; i++) { + uint8_t column_parity = 0; + for(j = 0; j < 4; j++) { + column_parity ^= (data >> (j * 8 + i)) & 1; + } + data_with_parity = (data_with_parity << 1) | column_parity; + } + + // bit 44 + data_with_parity = (data_with_parity << 1) | 0; + + return data_with_parity; +} + +static void em4305_start(void) { + furi_hal_rfid_tim_read_start(125000, 0.5); + + // do not ground the antenna + furi_hal_rfid_pin_pull_release(); +} + +static void em4305_stop(void) { + furi_hal_rfid_tim_read_stop(); + furi_hal_rfid_pins_reset(); +} + +static void em4305_write_bit(bool value) { + if(value) { + furi_delay_us(EM4305_TIMING_1 * 8); + } else { + furi_hal_rfid_tim_read_pause(); + furi_delay_us(EM4305_TIMING_0_OFF * 8); + furi_hal_rfid_tim_read_continue(); + furi_delay_us(EM4305_TIMING_0_ON * 8); + } +} + +static void em4305_write_opcode(uint8_t value) { + // 3 bit opcode + for(uint8_t i = 0; i < 3; i++) { + em4305_write_bit((value >> i) & 1); + } + + // parity + bool parity = 0; + for(uint8_t i = 0; i < 3; i++) { + parity ^= (value >> i) & 1; + } + em4305_write_bit(parity); +} + +static void em4305_field_stop() { + furi_hal_rfid_tim_read_pause(); + furi_delay_us(EM4305_FIELD_STOP_OFF_CYCLES * 8); + furi_hal_rfid_tim_read_continue(); + furi_delay_us(EM4305_FIELD_STOP_ON_CYCLES * 8); +} + +static void em4305_write_word(uint8_t address, uint32_t data) { + // parity + uint64_t data_with_parity = em4305_prepare_data(data); + + // power up the tag + furi_delay_us(8000); + + // field stop + em4305_field_stop(); + + // start bit + em4305_write_bit(0); + + // opcode + em4305_write_opcode(EM4x05_OPCODE_WRITE); + + // address + bool address_parity = 0; + for(uint8_t i = 0; i < 4; i++) { + em4305_write_bit((address >> (i)) & 1); + address_parity ^= (address >> (i)) & 1; + } + em4305_write_bit(0); + em4305_write_bit(0); + em4305_write_bit(address_parity); + + // data + for(uint8_t i = 0; i < 45; i++) { + em4305_write_bit((data_with_parity >> (44 - i)) & 1); + } + + // wait for power check and eeprom write + furi_delay_us(EM4305_TIMING_POWER_CHECK); + furi_delay_us(EM4305_TIMING_EEPROM_WRITE); +} + +void em4305_write(LFRFIDEM4305* data) { + furi_check(data); + + em4305_start(); + FURI_CRITICAL_ENTER(); + + for(uint8_t i = 0; i < EM4x05_WORD_COUNT; i++) { + if(data->mask & (1 << i)) { + em4305_write_word(i, data->word[i]); + } + } + + FURI_CRITICAL_EXIT(); + em4305_stop(); +} diff --git a/lib/lfrfid/tools/em4305.h b/lib/lfrfid/tools/em4305.h new file mode 100644 index 000000000..0cec00254 --- /dev/null +++ b/lib/lfrfid/tools/em4305.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// EM4305/4205 chip config definitions, thanks proxmark3! +#define EM4x05_GET_BITRATE(x) ((((x) & 0x3F) * 2) + 2) +// Note: only data rates 8, 16, 32, 40(*) and 64 are supported. (*) only with EM4305 330pF +#define EM4x05_SET_BITRATE(x) (((x) - 2) / 2) +#define EM4x05_MODULATION_NRZ (0x00000000) +#define EM4x05_MODULATION_MANCHESTER (0x00000040) +#define EM4x05_MODULATION_BIPHASE (0x00000080) +#define EM4x05_MODULATION_MILLER (0x000000C0) // not supported by all 4x05/4x69 chips +#define EM4x05_MODULATION_PSK1 (0x00000100) // not supported by all 4x05/4x69 chips +#define EM4x05_MODULATION_PSK2 (0x00000140) // not supported by all 4x05/4x69 chips +#define EM4x05_MODULATION_PSK3 (0x00000180) // not supported by all 4x05/4x69 chips +#define EM4x05_MODULATION_FSK1 (0x00000200) // not supported by all 4x05/4x69 chips +#define EM4x05_MODULATION_FSK2 (0x00000240) // not supported by all 4x05/4x69 chips +#define EM4x05_PSK_RF_2 (0) +#define EM4x05_PSK_RF_4 (0x00000400) +#define EM4x05_PSK_RF_8 (0x00000800) +#define EM4x05_MAXBLOCK_SHIFT (14) +#define EM4x05_FIRST_USER_BLOCK (5) +#define EM4x05_SET_NUM_BLOCKS(x) \ + (((x) + 4) << 14) // number of blocks sent during default read mode +#define EM4x05_GET_NUM_BLOCKS(x) ((((x) >> 14) & 0xF) - 4) +#define EM4x05_READ_LOGIN_REQ (1 << 18) +#define EM4x05_READ_HK_LOGIN_REQ (1 << 19) +#define EM4x05_WRITE_LOGIN_REQ (1 << 20) +#define EM4x05_WRITE_HK_LOGIN_REQ (1 << 21) +#define EM4x05_READ_AFTER_WRITE (1 << 22) +#define EM4x05_DISABLE_ALLOWED (1 << 23) +#define EM4x05_READER_TALK_FIRST (1 << 24) +#define EM4x05_INVERT (1 << 25) +#define EM4x05_PIGEON (1 << 26) + +#define EM4x05_WORD_COUNT (16) + +#define EM4x05_OPCODE_LOGIN (0b001) +#define EM4x05_OPCODE_WRITE (0b010) +#define EM4x05_OPCODE_READ (0b100) +#define EM4x05_OPCODE_PROTECT (0b110) +#define EM4x05_OPCODE_DISABLE (0b101) + +typedef struct { + uint32_t word[EM4x05_WORD_COUNT]; /**< Word data to write */ + uint16_t mask; /**< Word mask */ +} LFRFIDEM4305; + +/** Write EM4305 tag data to tag + * + * @param data The data to write (mask is taken from that data) + */ +void em4305_write(LFRFIDEM4305* data); + +#ifdef __cplusplus +} +#endif diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 29ed764e8..56bfbc2e6 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,79.2,, +Version,+,79.3,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 4a385d538..707acacff 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,79.2,, +Version,+,79.3,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -1000,6 +1000,7 @@ Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, size_t" Function,+,elements_text_box,void,"Canvas*, int32_t, int32_t, size_t, size_t, Align, Align, const char*, _Bool" Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, uint32_t, Elf32_Addr*" Function,+,elf_symbolname_hash,uint32_t,const char* +Function,+,em4305_write,void,LFRFIDEM4305* Function,+,empty_screen_alloc,EmptyScreen*, Function,+,empty_screen_free,void,EmptyScreen* Function,+,empty_screen_get_view,View*,EmptyScreen* From ac1b723436c927a2b34f2a83a48e63990fa9efb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 13 Feb 2025 03:53:14 +0900 Subject: [PATCH 08/14] Infrared: increase max carrier limit (#4070) Co-authored-by: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> --- targets/furi_hal_include/furi_hal_infrared.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/furi_hal_include/furi_hal_infrared.h b/targets/furi_hal_include/furi_hal_infrared.h index 29f7101c1..36eaf122d 100644 --- a/targets/furi_hal_include/furi_hal_infrared.h +++ b/targets/furi_hal_include/furi_hal_infrared.h @@ -13,7 +13,7 @@ extern "C" { #endif -#define INFRARED_MAX_FREQUENCY 56000 +#define INFRARED_MAX_FREQUENCY 1000000 #define INFRARED_MIN_FREQUENCY 10000 typedef enum { From e27f82f041d264341fe098e356f050eb0ef2aa61 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Thu, 13 Feb 2025 12:50:38 +0400 Subject: [PATCH 09/14] [FL-3925, FL-3942, FL-3944] JS features & bugfixes (SDK 0.2) (#4075) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: JS GPIO PWM, JS GUI Widget view; fix: JS EvtLoop stop on request, JS EvtLoop stop on error * fix: f18 build * docs: widget * fix: js unit test * change feature naming Co-authored-by: あく --- .../resources/unit_tests/js/basic.js | 2 +- applications/system/js_app/application.fam | 17 ++ .../js_app/examples/apps/Scripts/gpio.js | 8 + .../js_app/examples/apps/Scripts/gui.js | 44 +++ applications/system/js_app/js_modules.c | 2 + applications/system/js_app/js_modules.h | 14 +- applications/system/js_app/js_thread.c | 7 +- .../modules/js_event_loop/js_event_loop.c | 55 ++-- applications/system/js_app/modules/js_gpio.c | 103 ++++++- .../system/js_app/modules/js_gui/icon.c | 61 ++++ .../system/js_app/modules/js_gui/js_gui.c | 77 ++++- .../system/js_app/modules/js_gui/js_gui.h | 16 +- .../system/js_app/modules/js_gui/widget.c | 281 ++++++++++++++++++ .../js_app/packages/fz-sdk/gpio/index.d.ts | 28 ++ .../packages/fz-sdk/gui/byte_input.d.ts | 5 +- .../js_app/packages/fz-sdk/gui/dialog.d.ts | 5 +- .../packages/fz-sdk/gui/empty_screen.d.ts | 5 +- .../js_app/packages/fz-sdk/gui/icon.d.ts | 11 + .../js_app/packages/fz-sdk/gui/index.d.ts | 64 ++-- .../js_app/packages/fz-sdk/gui/loading.d.ts | 5 +- .../js_app/packages/fz-sdk/gui/submenu.d.ts | 5 +- .../js_app/packages/fz-sdk/gui/text_box.d.ts | 5 +- .../packages/fz-sdk/gui/text_input.d.ts | 5 +- .../js_app/packages/fz-sdk/gui/widget.d.ts | 66 ++++ .../js_app/packages/fz-sdk/package.json | 2 +- documentation/images/widget.png | Bin 0 -> 2390 bytes documentation/js/js_gui.md | 34 +-- documentation/js/js_gui__widget.md | 25 ++ lib/mjs/mjs_exec.c | 3 +- targets/f18/furi_hal/furi_hal_resources.h | 2 + targets/f7/furi_hal/furi_hal_pwm.h | 1 + targets/f7/furi_hal/furi_hal_resources.c | 2 + targets/f7/furi_hal/furi_hal_resources.h | 2 + 33 files changed, 858 insertions(+), 104 deletions(-) create mode 100644 applications/system/js_app/modules/js_gui/icon.c create mode 100644 applications/system/js_app/modules/js_gui/widget.c create mode 100644 applications/system/js_app/packages/fz-sdk/gui/icon.d.ts create mode 100644 applications/system/js_app/packages/fz-sdk/gui/widget.d.ts create mode 100644 documentation/images/widget.png create mode 100644 documentation/js/js_gui__widget.md diff --git a/applications/debug/unit_tests/resources/unit_tests/js/basic.js b/applications/debug/unit_tests/resources/unit_tests/js/basic.js index a08041e9f..26f3f68f5 100644 --- a/applications/debug/unit_tests/resources/unit_tests/js/basic.js +++ b/applications/debug/unit_tests/resources/unit_tests/js/basic.js @@ -12,4 +12,4 @@ tests.assert_eq(false, doesSdkSupport(["abobus", "other-nonexistent-feature"])); tests.assert_eq("flipperdevices", flipper.firmwareVendor); tests.assert_eq(0, flipper.jsSdkVersion[0]); -tests.assert_eq(1, flipper.jsSdkVersion[1]); +tests.assert_eq(2, flipper.jsSdkVersion[1]); diff --git a/applications/system/js_app/application.fam b/applications/system/js_app/application.fam index 73bdde21e..db1521b9d 100644 --- a/applications/system/js_app/application.fam +++ b/applications/system/js_app/application.fam @@ -110,6 +110,23 @@ App( fap_libs=["assets"], ) +App( + appid="js_gui__widget", + apptype=FlipperAppType.PLUGIN, + entry_point="js_view_widget_ep", + requires=["js_app"], + sources=["modules/js_gui/widget.c"], +) + +App( + appid="js_gui__icon", + apptype=FlipperAppType.PLUGIN, + entry_point="js_gui_icon_ep", + requires=["js_app"], + sources=["modules/js_gui/icon.c"], + fap_libs=["assets"], +) + App( appid="js_notification", apptype=FlipperAppType.PLUGIN, diff --git a/applications/system/js_app/examples/apps/Scripts/gpio.js b/applications/system/js_app/examples/apps/Scripts/gpio.js index 24d0f0286..6ea0a948f 100644 --- a/applications/system/js_app/examples/apps/Scripts/gpio.js +++ b/applications/system/js_app/examples/apps/Scripts/gpio.js @@ -3,6 +3,7 @@ let gpio = require("gpio"); // initialize pins let led = gpio.get("pc3"); // same as `gpio.get(7)` +let led2 = gpio.get("pa7"); // same as `gpio.get(2)` let pot = gpio.get("pc0"); // same as `gpio.get(16)` let button = gpio.get("pc1"); // same as `gpio.get(15)` led.init({ direction: "out", outMode: "push_pull" }); @@ -16,6 +17,13 @@ eventLoop.subscribe(eventLoop.timer("periodic", 1000), function (_, _item, led, return [led, !state]; }, led, true); +// cycle led pwm +print("Commencing PWM (PA7)"); +eventLoop.subscribe(eventLoop.timer("periodic", 10), function (_, _item, led2, state) { + led2.pwmWrite(10000, state); + return [led2, (state + 1) % 101]; +}, led2, 0); + // read potentiometer when button is pressed print("Press the button (PC1)"); eventLoop.subscribe(button.interrupt(), function (_, _item, pot) { diff --git a/applications/system/js_app/examples/apps/Scripts/gui.js b/applications/system/js_app/examples/apps/Scripts/gui.js index a1e023853..a1c104cf1 100644 --- a/applications/system/js_app/examples/apps/Scripts/gui.js +++ b/applications/system/js_app/examples/apps/Scripts/gui.js @@ -9,8 +9,23 @@ let byteInputView = require("gui/byte_input"); let textBoxView = require("gui/text_box"); let dialogView = require("gui/dialog"); let filePicker = require("gui/file_picker"); +let widget = require("gui/widget"); +let icon = require("gui/icon"); let flipper = require("flipper"); +// declare clock widget children +let cuteDolphinWithWatch = icon.getBuiltin("DolphinWait_59x54"); +let jsLogo = icon.getBuiltin("js_script_10px"); +let stopwatchWidgetElements = [ + { element: "string", x: 67, y: 44, align: "bl", font: "big_numbers", text: "00 00" }, + { element: "string", x: 77, y: 22, align: "bl", font: "primary", text: "Stopwatch" }, + { element: "frame", x: 64, y: 27, w: 28, h: 20, radius: 3 }, + { element: "frame", x: 100, y: 27, w: 28, h: 20, radius: 3 }, + { element: "icon", x: 0, y: 5, iconData: cuteDolphinWithWatch }, + { element: "icon", x: 64, y: 13, iconData: jsLogo }, + { element: "button", button: "right", text: "Back" }, +]; + // declare view instances let views = { loading: loadingView.make(), @@ -31,6 +46,7 @@ let views = { longText: textBoxView.makeWith({ text: "This is a very long string that demonstrates the TextBox view. Use the D-Pad to scroll backwards and forwards.\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse rhoncus est malesuada quam egestas ultrices. Maecenas non eros a nulla eleifend vulputate et ut risus. Quisque in mauris mattis, venenatis risus eget, aliquam diam. Fusce pretium feugiat mauris, ut faucibus ex volutpat in. Phasellus volutpat ex sed gravida consectetur. Aliquam sed lectus feugiat, tristique lectus et, bibendum lacus. Ut sit amet augue eu sapien elementum aliquam quis vitae tortor. Vestibulum quis commodo odio. In elementum fermentum massa, eu pellentesque nibh cursus at. Integer eleifend lacus nec purus elementum sodales. Nulla elementum neque urna, non vulputate massa semper sed. Fusce ut nisi vitae dui blandit congue pretium vitae turpis.", }), + stopwatchWidget: widget.makeWith({}, stopwatchWidgetElements), demos: submenuView.makeWith({ header: "Choose a demo", items: [ @@ -40,6 +56,7 @@ let views = { "Byte input", "Text box", "File picker", + "Widget", "Exit app", ], }), @@ -72,6 +89,8 @@ eventLoop.subscribe(views.demos.chosen, function (_sub, index, gui, eventLoop, v views.helloDialog.set("center", "Nice!"); gui.viewDispatcher.switchTo(views.helloDialog); } else if (index === 6) { + gui.viewDispatcher.switchTo(views.stopwatchWidget); + } else if (index === 7) { eventLoop.stop(); } }, gui, eventLoop, views); @@ -111,6 +130,31 @@ eventLoop.subscribe(gui.viewDispatcher.navigation, function (_sub, _, gui, views gui.viewDispatcher.switchTo(views.demos); }, gui, views, eventLoop); +// go to the demo chooser screen when the right key is pressed on the widget screen +eventLoop.subscribe(views.stopwatchWidget.button, function (_sub, buttonId, gui, views) { + if (buttonId === "right") + gui.viewDispatcher.switchTo(views.demos); +}, gui, views); + +// count time +eventLoop.subscribe(eventLoop.timer("periodic", 500), function (_sub, _item, views, stopwatchWidgetElements, halfSeconds) { + let text = (halfSeconds / 2 / 60).toString(); + if (halfSeconds < 10 * 60 * 2) + text = "0" + text; + + text += (halfSeconds % 2 === 0) ? ":" : " "; + + if (((halfSeconds / 2) % 60) < 10) + text += "0"; + text += ((halfSeconds / 2) % 60).toString(); + + stopwatchWidgetElements[0].text = text; + views.stopwatchWidget.setChildren(stopwatchWidgetElements); + + halfSeconds++; + return [views, stopwatchWidgetElements, halfSeconds]; +}, views, stopwatchWidgetElements, 0); + // run UI gui.viewDispatcher.switchTo(views.demos); eventLoop.run(); diff --git a/applications/system/js_app/js_modules.c b/applications/system/js_app/js_modules.c index bffa553a8..47bdd516c 100644 --- a/applications/system/js_app/js_modules.c +++ b/applications/system/js_app/js_modules.c @@ -267,6 +267,8 @@ void js_check_sdk_compatibility(struct mjs* mjs) { static const char* extra_features[] = { "baseline", // dummy "feature" + "gpio-pwm", + "gui-widget", }; /** diff --git a/applications/system/js_app/js_modules.h b/applications/system/js_app/js_modules.h index 1dfd59521..29de72642 100644 --- a/applications/system/js_app/js_modules.h +++ b/applications/system/js_app/js_modules.h @@ -11,7 +11,7 @@ #define JS_SDK_VENDOR "flipperdevices" #define JS_SDK_MAJOR 0 -#define JS_SDK_MINOR 1 +#define JS_SDK_MINOR 2 /** * @brief Returns the foreign pointer in `obj["_"]` @@ -254,6 +254,18 @@ static inline void return; \ } while(0) +/** + * @brief Prepends an error, sets the JS return value to `undefined` and returns + * a value C function + * @warning This macro executes `return;` by design + */ +#define JS_ERROR_AND_RETURN_VAL(mjs, error_code, ret_val, ...) \ + do { \ + mjs_prepend_errorf(mjs, error_code, __VA_ARGS__); \ + mjs_return(mjs, MJS_UNDEFINED); \ + return ret_val; \ + } while(0) + typedef struct JsModules JsModules; typedef void* (*JsModuleConstructor)(struct mjs* mjs, mjs_val_t* object, JsModules* modules); diff --git a/applications/system/js_app/js_thread.c b/applications/system/js_app/js_thread.c index 600c2676e..4a6d23011 100644 --- a/applications/system/js_app/js_thread.c +++ b/applications/system/js_app/js_thread.c @@ -92,7 +92,7 @@ static void js_console_debug(struct mjs* mjs) { } static void js_exit_flag_poll(struct mjs* mjs) { - uint32_t flags = furi_thread_flags_wait(ThreadEventStop, FuriFlagWaitAny, 0); + uint32_t flags = furi_thread_flags_wait(ThreadEventStop, FuriFlagWaitAny | FuriFlagNoClear, 0); if(flags & FuriFlagError) { return; } @@ -102,7 +102,8 @@ static void js_exit_flag_poll(struct mjs* mjs) { } bool js_delay_with_flags(struct mjs* mjs, uint32_t time) { - uint32_t flags = furi_thread_flags_wait(ThreadEventStop, FuriFlagWaitAny, time); + uint32_t flags = + furi_thread_flags_wait(ThreadEventStop, FuriFlagWaitAny | FuriFlagNoClear, time); if(flags & FuriFlagError) { return false; } @@ -124,7 +125,7 @@ uint32_t js_flags_wait(struct mjs* mjs, uint32_t flags_mask, uint32_t timeout) { uint32_t flags = furi_thread_flags_get(); furi_check((flags & FuriFlagError) == 0); if(flags == 0) { - flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny, timeout); + flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny | FuriFlagNoClear, timeout); } else { uint32_t state = furi_thread_flags_clear(flags & flags_mask); furi_check((state & FuriFlagError) == 0); diff --git a/applications/system/js_app/modules/js_event_loop/js_event_loop.c b/applications/system/js_app/modules/js_event_loop/js_event_loop.c index 7f45c1a0f..625301ad1 100644 --- a/applications/system/js_app/modules/js_event_loop/js_event_loop.c +++ b/applications/system/js_app/modules/js_event_loop/js_event_loop.c @@ -12,6 +12,7 @@ * @brief Context passed to the generic event callback */ typedef struct { + FuriEventLoop* event_loop; JsEventLoopObjectType object_type; struct mjs* mjs; @@ -36,11 +37,6 @@ typedef struct { void* subscriptions; // SubscriptionArray_t, which we can't reference in this definition } JsEventLoopSubscription; -typedef struct { - FuriEventLoop* loop; - struct mjs* mjs; -} JsEventLoopTickContext; - ARRAY_DEF(SubscriptionArray, JsEventLoopSubscription*, M_PTR_OPLIST); //-V575 ARRAY_DEF(ContractArray, JsEventLoopContract*, M_PTR_OPLIST); //-V575 @@ -51,7 +47,6 @@ struct JsEventLoop { FuriEventLoop* loop; SubscriptionArray_t subscriptions; ContractArray_t owned_contracts; //mjs, &result, context->callback, @@ -68,6 +63,12 @@ static void js_event_loop_callback_generic(void* param) { context->arity, context->arguments); + bool is_error = strcmp(mjs_strerror(context->mjs, error), "NO_ERROR") != 0; + bool asked_to_stop = js_flags_wait(context->mjs, ThreadEventStop, 0) & ThreadEventStop; + if(is_error || asked_to_stop) { + furi_event_loop_stop(context->event_loop); + } + // save returned args for next call if(mjs_array_length(context->mjs, result) != context->arity - SYSTEM_ARGS) return; for(size_t i = 0; i < context->arity - SYSTEM_ARGS; i++) { @@ -111,11 +112,14 @@ static void js_event_loop_subscription_cancel(struct mjs* mjs) { JsEventLoopSubscription* subscription = JS_GET_CONTEXT(mjs); if(subscription->object_type == JsEventLoopObjectTypeTimer) { + // timer operations are deferred, which creates lifetime issues + // just stop the timer and let the cleanup routine free everything when the script is done furi_event_loop_timer_stop(subscription->object); - } else { - furi_event_loop_unsubscribe(subscription->loop, subscription->object); + return; } + furi_event_loop_unsubscribe(subscription->loop, subscription->object); + free(subscription->context->arguments); free(subscription->context); @@ -158,6 +162,7 @@ static void js_event_loop_subscribe(struct mjs* mjs) { mjs_set(mjs, subscription_obj, "cancel", ~0, MJS_MK_FN(js_event_loop_subscription_cancel)); // create callback context + context->event_loop = module->loop; context->object_type = contract->object_type; context->arity = mjs_nargs(mjs) - SYSTEM_ARGS + 2; context->arguments = calloc(context->arity, sizeof(mjs_val_t)); @@ -333,37 +338,22 @@ static void js_event_loop_queue(struct mjs* mjs) { mjs_return(mjs, queue); } -static void js_event_loop_tick(void* param) { - JsEventLoopTickContext* context = param; - uint32_t flags = furi_thread_flags_wait(ThreadEventStop, FuriFlagWaitAny | FuriFlagNoClear, 0); - if(flags & FuriFlagError) { - return; - } - if(flags & ThreadEventStop) { - furi_event_loop_stop(context->loop); - mjs_exit(context->mjs); - } -} - static void* js_event_loop_create(struct mjs* mjs, mjs_val_t* object, JsModules* modules) { UNUSED(modules); mjs_val_t event_loop_obj = mjs_mk_object(mjs); JsEventLoop* module = malloc(sizeof(JsEventLoop)); - JsEventLoopTickContext* tick_ctx = malloc(sizeof(JsEventLoopTickContext)); module->loop = furi_event_loop_alloc(); - tick_ctx->loop = module->loop; - tick_ctx->mjs = mjs; - module->tick_context = tick_ctx; - furi_event_loop_tick_set(module->loop, 10, js_event_loop_tick, tick_ctx); SubscriptionArray_init(module->subscriptions); ContractArray_init(module->owned_contracts); - mjs_set(mjs, event_loop_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, module)); - mjs_set(mjs, event_loop_obj, "subscribe", ~0, MJS_MK_FN(js_event_loop_subscribe)); - mjs_set(mjs, event_loop_obj, "run", ~0, MJS_MK_FN(js_event_loop_run)); - mjs_set(mjs, event_loop_obj, "stop", ~0, MJS_MK_FN(js_event_loop_stop)); - mjs_set(mjs, event_loop_obj, "timer", ~0, MJS_MK_FN(js_event_loop_timer)); - mjs_set(mjs, event_loop_obj, "queue", ~0, MJS_MK_FN(js_event_loop_queue)); + JS_ASSIGN_MULTI(mjs, event_loop_obj) { + JS_FIELD(INST_PROP_NAME, mjs_mk_foreign(mjs, module)); + JS_FIELD("subscribe", MJS_MK_FN(js_event_loop_subscribe)); + JS_FIELD("run", MJS_MK_FN(js_event_loop_run)); + JS_FIELD("stop", MJS_MK_FN(js_event_loop_stop)); + JS_FIELD("timer", MJS_MK_FN(js_event_loop_timer)); + JS_FIELD("queue", MJS_MK_FN(js_event_loop_queue)); + } *object = event_loop_obj; return module; @@ -418,7 +408,6 @@ static void js_event_loop_destroy(void* inst) { ContractArray_clear(module->owned_contracts); furi_event_loop_free(module->loop); - free(module->tick_context); free(module); } } diff --git a/applications/system/js_app/modules/js_gpio.c b/applications/system/js_app/modules/js_gpio.c index ae3fefd71..23884a6d4 100644 --- a/applications/system/js_app/modules/js_gpio.c +++ b/applications/system/js_app/modules/js_gpio.c @@ -1,6 +1,7 @@ #include "../js_modules.h" // IWYU pragma: keep #include "./js_event_loop/js_event_loop.h" #include +#include #include #include #include @@ -17,6 +18,7 @@ typedef struct { FuriSemaphore* interrupt_semaphore; JsEventLoopContract* interrupt_contract; FuriHalAdcChannel adc_channel; + FuriHalPwmOutputId pwm_output; FuriHalAdcHandle* adc_handle; } JsGpioPinInst; @@ -231,6 +233,88 @@ static void js_gpio_read_analog(struct mjs* mjs) { mjs_return(mjs, mjs_mk_number(mjs, (double)millivolts)); } +/** + * @brief Determines whether this pin supports PWM + * + * Example usage: + * + * ```js + * let gpio = require("gpio"); + * assert_eq(true, gpio.get("pa4").isPwmSupported()); + * assert_eq(false, gpio.get("pa5").isPwmSupported()); + * ``` + */ +static void js_gpio_is_pwm_supported(struct mjs* mjs) { + JsGpioPinInst* manager_data = JS_GET_CONTEXT(mjs); + mjs_return(mjs, mjs_mk_boolean(mjs, manager_data->pwm_output != FuriHalPwmOutputIdNone)); +} + +/** + * @brief Sets PWM parameters and starts the PWM + * + * Example usage: + * + * ```js + * let gpio = require("gpio"); + * let pa4 = gpio.get("pa4"); + * pa4.pwmWrite(10000, 50); + * ``` + */ +static void js_gpio_pwm_write(struct mjs* mjs) { + JsGpioPinInst* manager_data = JS_GET_CONTEXT(mjs); + int32_t frequency, duty; + JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_INT32(&frequency), JS_ARG_INT32(&duty)); + if(manager_data->pwm_output == FuriHalPwmOutputIdNone) { + JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "PWM is not supported on this pin"); + } + + if(furi_hal_pwm_is_running(manager_data->pwm_output)) { + furi_hal_pwm_set_params(manager_data->pwm_output, frequency, duty); + } else { + furi_hal_pwm_start(manager_data->pwm_output, frequency, duty); + } +} + +/** + * @brief Determines whether PWM is running + * + * Example usage: + * + * ```js + * let gpio = require("gpio"); + * assert_eq(false, gpio.get("pa4").isPwmRunning()); + * ``` + */ +static void js_gpio_is_pwm_running(struct mjs* mjs) { + JsGpioPinInst* manager_data = JS_GET_CONTEXT(mjs); + if(manager_data->pwm_output == FuriHalPwmOutputIdNone) { + JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "PWM is not supported on this pin"); + } + + mjs_return(mjs, mjs_mk_boolean(mjs, furi_hal_pwm_is_running(manager_data->pwm_output))); +} + +/** + * @brief Stops PWM + * + * Example usage: + * + * ```js + * let gpio = require("gpio"); + * let pa4 = gpio.get("pa4"); + * pa4.pwmWrite(10000, 50); + * pa4.pwmStop(); + * ``` + */ +static void js_gpio_pwm_stop(struct mjs* mjs) { + JsGpioPinInst* manager_data = JS_GET_CONTEXT(mjs); + if(manager_data->pwm_output != FuriHalPwmOutputIdNone) { + JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "PWM is not supported on this pin"); + } + + furi_hal_pwm_stop(manager_data->pwm_output); +} + /** * @brief Returns an object that manages a specified pin. * @@ -269,12 +353,19 @@ static void js_gpio_get(struct mjs* mjs) { manager_data->interrupt_semaphore = furi_semaphore_alloc(UINT32_MAX, 0); manager_data->adc_handle = module->adc_handle; manager_data->adc_channel = pin_record->channel; - mjs_set(mjs, manager, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, manager_data)); - mjs_set(mjs, manager, "init", ~0, MJS_MK_FN(js_gpio_init)); - mjs_set(mjs, manager, "write", ~0, MJS_MK_FN(js_gpio_write)); - mjs_set(mjs, manager, "read", ~0, MJS_MK_FN(js_gpio_read)); - mjs_set(mjs, manager, "readAnalog", ~0, MJS_MK_FN(js_gpio_read_analog)); - mjs_set(mjs, manager, "interrupt", ~0, MJS_MK_FN(js_gpio_interrupt)); + manager_data->pwm_output = pin_record->pwm_output; + JS_ASSIGN_MULTI(mjs, manager) { + JS_FIELD(INST_PROP_NAME, mjs_mk_foreign(mjs, manager_data)); + JS_FIELD("init", MJS_MK_FN(js_gpio_init)); + JS_FIELD("write", MJS_MK_FN(js_gpio_write)); + JS_FIELD("read", MJS_MK_FN(js_gpio_read)); + JS_FIELD("readAnalog", MJS_MK_FN(js_gpio_read_analog)); + JS_FIELD("interrupt", MJS_MK_FN(js_gpio_interrupt)); + JS_FIELD("isPwmSupported", MJS_MK_FN(js_gpio_is_pwm_supported)); + JS_FIELD("pwmWrite", MJS_MK_FN(js_gpio_pwm_write)); + JS_FIELD("isPwmRunning", MJS_MK_FN(js_gpio_is_pwm_running)); + JS_FIELD("pwmStop", MJS_MK_FN(js_gpio_pwm_stop)); + } mjs_return(mjs, manager); // remember pin diff --git a/applications/system/js_app/modules/js_gui/icon.c b/applications/system/js_app/modules/js_gui/icon.c new file mode 100644 index 000000000..4b7926ba1 --- /dev/null +++ b/applications/system/js_app/modules/js_gui/icon.c @@ -0,0 +1,61 @@ +#include "../../js_modules.h" +#include + +typedef struct { + const char* name; + const Icon* data; +} IconDefinition; + +#define ICON_DEF(icon) \ + (IconDefinition) { \ + .name = #icon, .data = &I_##icon \ + } + +static const IconDefinition builtin_icons[] = { + ICON_DEF(DolphinWait_59x54), + ICON_DEF(js_script_10px), +}; + +static void js_gui_icon_get_builtin(struct mjs* mjs) { + const char* icon_name; + JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&icon_name)); + + for(size_t i = 0; i < COUNT_OF(builtin_icons); i++) { + if(strcmp(icon_name, builtin_icons[i].name) == 0) { + mjs_return(mjs, mjs_mk_foreign(mjs, (void*)builtin_icons[i].data)); + return; + } + } + + JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "no such built-in icon"); +} + +static void* js_gui_icon_create(struct mjs* mjs, mjs_val_t* object, JsModules* modules) { + UNUSED(modules); + *object = mjs_mk_object(mjs); + JS_ASSIGN_MULTI(mjs, *object) { + JS_FIELD("getBuiltin", MJS_MK_FN(js_gui_icon_get_builtin)); + } + return NULL; +} + +static void js_gui_icon_destroy(void* inst) { + UNUSED(inst); +} + +static const JsModuleDescriptor js_gui_icon_desc = { + "gui__icon", + js_gui_icon_create, + js_gui_icon_destroy, + NULL, +}; + +static const FlipperAppPluginDescriptor plugin_descriptor = { + .appid = PLUGIN_APP_ID, + .ep_api_version = PLUGIN_API_VERSION, + .entry_point = &js_gui_icon_desc, +}; + +const FlipperAppPluginDescriptor* js_gui_icon_ep(void) { + return &plugin_descriptor; +} diff --git a/applications/system/js_app/modules/js_gui/js_gui.c b/applications/system/js_app/modules/js_gui/js_gui.c index 22d04855d..e505681df 100644 --- a/applications/system/js_app/modules/js_gui/js_gui.c +++ b/applications/system/js_app/modules/js_gui/js_gui.c @@ -247,6 +247,22 @@ static bool return false; } +/** + * @brief Sets the list of children. Not available from JS. + */ +static bool + js_gui_view_internal_set_children(struct mjs* mjs, mjs_val_t children, JsGuiViewData* data) { + data->descriptor->reset_children(data->specific_view, data->custom_data); + + for(size_t i = 0; i < mjs_array_length(mjs, children); i++) { + mjs_val_t child = mjs_array_get(mjs, children, i); + if(!data->descriptor->add_child(mjs, data->specific_view, data->custom_data, child)) + return false; + } + + return true; +} + /** * @brief `View.set` */ @@ -260,6 +276,46 @@ static void js_gui_view_set(struct mjs* mjs) { mjs_return(mjs, MJS_UNDEFINED); } +/** + * @brief `View.addChild` + */ +static void js_gui_view_add_child(struct mjs* mjs) { + JsGuiViewData* data = JS_GET_CONTEXT(mjs); + if(!data->descriptor->add_child || !data->descriptor->reset_children) + JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "this View can't have children"); + + mjs_val_t child; + JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ANY(&child)); + bool success = data->descriptor->add_child(mjs, data->specific_view, data->custom_data, child); + UNUSED(success); + mjs_return(mjs, MJS_UNDEFINED); +} + +/** + * @brief `View.resetChildren` + */ +static void js_gui_view_reset_children(struct mjs* mjs) { + JsGuiViewData* data = JS_GET_CONTEXT(mjs); + if(!data->descriptor->add_child || !data->descriptor->reset_children) + JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "this View can't have children"); + + data->descriptor->reset_children(data->specific_view, data->custom_data); + mjs_return(mjs, MJS_UNDEFINED); +} + +/** + * @brief `View.setChildren` + */ +static void js_gui_view_set_children(struct mjs* mjs) { + JsGuiViewData* data = JS_GET_CONTEXT(mjs); + if(!data->descriptor->add_child || !data->descriptor->reset_children) + JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "this View can't have children"); + + mjs_val_t children; + JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ARR(&children)); + js_gui_view_internal_set_children(mjs, children, data); +} + /** * @brief `View` destructor */ @@ -283,7 +339,12 @@ static mjs_val_t js_gui_make_view(struct mjs* mjs, const JsViewDescriptor* descr // generic view API mjs_val_t view_obj = mjs_mk_object(mjs); - mjs_set(mjs, view_obj, "set", ~0, MJS_MK_FN(js_gui_view_set)); + JS_ASSIGN_MULTI(mjs, view_obj) { + JS_FIELD("set", MJS_MK_FN(js_gui_view_set)); + JS_FIELD("addChild", MJS_MK_FN(js_gui_view_add_child)); + JS_FIELD("resetChildren", MJS_MK_FN(js_gui_view_reset_children)); + JS_FIELD("setChildren", MJS_MK_FN(js_gui_view_set_children)); + } // object data JsGuiViewData* data = malloc(sizeof(JsGuiViewData)); @@ -314,7 +375,7 @@ static void js_gui_vf_make(struct mjs* mjs) { */ static void js_gui_vf_make_with(struct mjs* mjs) { mjs_val_t props; - JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_OBJ(&props)); + JS_FETCH_ARGS_OR_RETURN(mjs, JS_AT_LEAST, JS_ARG_OBJ(&props)); const JsViewDescriptor* descriptor = JS_GET_CONTEXT(mjs); // make the object like normal @@ -334,6 +395,18 @@ static void js_gui_vf_make_with(struct mjs* mjs) { } } + // assign children + if(mjs_nargs(mjs) >= 2) { + if(!data->descriptor->add_child || !data->descriptor->reset_children) + JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "this View can't have children"); + + mjs_val_t children = mjs_arg(mjs, 1); + if(!mjs_is_array(children)) + JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "argument 1: expected array"); + + if(!js_gui_view_internal_set_children(mjs, children, data)) return; + } + mjs_return(mjs, view_obj); } diff --git a/applications/system/js_app/modules/js_gui/js_gui.h b/applications/system/js_app/modules/js_gui/js_gui.h index d400d0a33..d9d98df39 100644 --- a/applications/system/js_app/modules/js_gui/js_gui.h +++ b/applications/system/js_app/modules/js_gui/js_gui.h @@ -50,6 +50,11 @@ typedef void (*JsViewFree)(void* specific_view); typedef void* (*JsViewCustomMake)(struct mjs* mjs, void* specific_view, mjs_val_t view_obj); /** @brief Context destruction for glue code */ typedef void (*JsViewCustomDestroy)(void* specific_view, void* custom_state, FuriEventLoop* loop); +/** @brief `addChild` callback for glue code */ +typedef bool ( + *JsViewAddChild)(struct mjs* mjs, void* specific_view, void* custom_state, mjs_val_t child_obj); +/** @brief `resetChildren` callback for glue code */ +typedef void (*JsViewResetChildren)(void* specific_view, void* custom_state); /** * @brief Descriptor for a JS view @@ -66,15 +71,22 @@ typedef struct { JsViewAlloc alloc; JsViewGetView get_view; JsViewFree free; + JsViewCustomMake custom_make; // get_view -> [custom_make (if set)] -> props[i].assign -> [custom_destroy (if_set)] -> free -// \_______________ creation ________________/ \___ usage ___/ \_________ destruction _________/ +// +-> add_child -+ +// +-> reset_children -+ +// alloc -> get_view -> custom_make -+-> props[i].assign -+> custom_destroy -> free +// \__________ creation __________/ \____ use ____/ \___ destruction ____/ /** * @brief Creates a JS `ViewFactory` object diff --git a/applications/system/js_app/modules/js_gui/widget.c b/applications/system/js_app/modules/js_gui/widget.c new file mode 100644 index 000000000..5f9a222cc --- /dev/null +++ b/applications/system/js_app/modules/js_gui/widget.c @@ -0,0 +1,281 @@ +#include "../../js_modules.h" // IWYU pragma: keep +#include "js_gui.h" +#include "../js_event_loop/js_event_loop.h" +#include + +typedef struct { + FuriMessageQueue* queue; + JsEventLoopContract contract; +} JsWidgetCtx; + +#define QUEUE_LEN 2 + +/** + * @brief Parses position (X and Y) from an element declaration object + */ +static bool element_get_position(struct mjs* mjs, mjs_val_t element, int32_t* x, int32_t* y) { + mjs_val_t x_in = mjs_get(mjs, element, "x", ~0); + mjs_val_t y_in = mjs_get(mjs, element, "y", ~0); + if(!mjs_is_number(x_in) || !mjs_is_number(y_in)) return false; + *x = mjs_get_int32(mjs, x_in); + *y = mjs_get_int32(mjs, y_in); + return true; +} + +/** + * @brief Parses size (W and h) from an element declaration object + */ +static bool element_get_size(struct mjs* mjs, mjs_val_t element, int32_t* w, int32_t* h) { + mjs_val_t w_in = mjs_get(mjs, element, "w", ~0); + mjs_val_t h_in = mjs_get(mjs, element, "h", ~0); + if(!mjs_is_number(w_in) || !mjs_is_number(h_in)) return false; + *w = mjs_get_int32(mjs, w_in); + *h = mjs_get_int32(mjs, h_in); + return true; +} + +/** + * @brief Parses alignment (V and H) from an element declaration object + */ +static bool + element_get_alignment(struct mjs* mjs, mjs_val_t element, Align* align_v, Align* align_h) { + mjs_val_t align_in = mjs_get(mjs, element, "align", ~0); + const char* align = mjs_get_string(mjs, &align_in, NULL); + if(!align) return false; + if(strlen(align) != 2) return false; + + if(align[0] == 't') { + *align_v = AlignTop; + } else if(align[0] == 'c') { + *align_v = AlignCenter; + } else if(align[0] == 'b') { + *align_v = AlignBottom; + } else { + return false; + } + + if(align[1] == 'l') { + *align_h = AlignLeft; + } else if(align[1] == 'm') { // m = middle + *align_h = AlignCenter; + } else if(align[1] == 'r') { + *align_h = AlignRight; + } else { + return false; + } + + return true; +} + +/** + * @brief Parses font from an element declaration object + */ +static bool element_get_font(struct mjs* mjs, mjs_val_t element, Font* font) { + mjs_val_t font_in = mjs_get(mjs, element, "font", ~0); + const char* font_str = mjs_get_string(mjs, &font_in, NULL); + if(!font_str) return false; + + if(strcmp(font_str, "primary") == 0) { + *font = FontPrimary; + } else if(strcmp(font_str, "secondary") == 0) { + *font = FontSecondary; + } else if(strcmp(font_str, "keyboard") == 0) { + *font = FontKeyboard; + } else if(strcmp(font_str, "big_numbers") == 0) { + *font = FontBigNumbers; + } else { + return false; + } + return true; +} + +/** + * @brief Parses text from an element declaration object + */ +static bool element_get_text(struct mjs* mjs, mjs_val_t element, mjs_val_t* text) { + *text = mjs_get(mjs, element, "text", ~0); + return mjs_is_string(*text); +} + +/** + * @brief Widget button element callback + */ +static void js_widget_button_callback(GuiButtonType result, InputType type, JsWidgetCtx* context) { + UNUSED(type); + furi_check(furi_message_queue_put(context->queue, &result, 0) == FuriStatusOk); +} + +#define DESTRUCTURE_OR_RETURN(mjs, child_obj, part, ...) \ + if(!element_get_##part(mjs, child_obj, __VA_ARGS__)) \ + JS_ERROR_AND_RETURN_VAL(mjs, MJS_BAD_ARGS_ERROR, false, "failed to fetch element " #part); + +static bool js_widget_add_child( + struct mjs* mjs, + Widget* widget, + JsWidgetCtx* context, + mjs_val_t child_obj) { + UNUSED(context); + if(!mjs_is_object(child_obj)) + JS_ERROR_AND_RETURN_VAL(mjs, MJS_BAD_ARGS_ERROR, false, "child must be an object"); + + mjs_val_t element_type_term = mjs_get(mjs, child_obj, "element", ~0); + const char* element_type = mjs_get_string(mjs, &element_type_term, NULL); + if(!element_type) + JS_ERROR_AND_RETURN_VAL( + mjs, MJS_BAD_ARGS_ERROR, false, "child object must have `element` property"); + + if((strcmp(element_type, "string") == 0) || (strcmp(element_type, "string_multiline") == 0)) { + int32_t x, y; + Align align_v, align_h; + Font font; + mjs_val_t text; + DESTRUCTURE_OR_RETURN(mjs, child_obj, position, &x, &y); + DESTRUCTURE_OR_RETURN(mjs, child_obj, alignment, &align_v, &align_h); + DESTRUCTURE_OR_RETURN(mjs, child_obj, font, &font); + DESTRUCTURE_OR_RETURN(mjs, child_obj, text, &text); + if(strcmp(element_type, "string") == 0) { + widget_add_string_element( + widget, x, y, align_h, align_v, font, mjs_get_string(mjs, &text, NULL)); + } else { + widget_add_string_multiline_element( + widget, x, y, align_h, align_v, font, mjs_get_string(mjs, &text, NULL)); + } + + } else if(strcmp(element_type, "text_box") == 0) { + int32_t x, y, w, h; + Align align_v, align_h; + Font font; + mjs_val_t text; + DESTRUCTURE_OR_RETURN(mjs, child_obj, position, &x, &y); + DESTRUCTURE_OR_RETURN(mjs, child_obj, size, &w, &h); + DESTRUCTURE_OR_RETURN(mjs, child_obj, alignment, &align_v, &align_h); + DESTRUCTURE_OR_RETURN(mjs, child_obj, font, &font); + DESTRUCTURE_OR_RETURN(mjs, child_obj, text, &text); + mjs_val_t strip_to_dots_in = mjs_get(mjs, child_obj, "stripToDots", ~0); + if(!mjs_is_boolean(strip_to_dots_in)) + JS_ERROR_AND_RETURN_VAL( + mjs, MJS_BAD_ARGS_ERROR, false, "failed to fetch element stripToDots"); + bool strip_to_dots = mjs_get_bool(mjs, strip_to_dots_in); + widget_add_text_box_element( + widget, x, y, w, h, align_h, align_v, mjs_get_string(mjs, &text, NULL), strip_to_dots); + + } else if(strcmp(element_type, "text_scroll") == 0) { + int32_t x, y, w, h; + mjs_val_t text; + DESTRUCTURE_OR_RETURN(mjs, child_obj, position, &x, &y); + DESTRUCTURE_OR_RETURN(mjs, child_obj, size, &w, &h); + DESTRUCTURE_OR_RETURN(mjs, child_obj, text, &text); + widget_add_text_scroll_element(widget, x, y, w, h, mjs_get_string(mjs, &text, NULL)); + + } else if(strcmp(element_type, "button") == 0) { + mjs_val_t btn_in = mjs_get(mjs, child_obj, "button", ~0); + const char* btn_name = mjs_get_string(mjs, &btn_in, NULL); + if(!btn_name) + JS_ERROR_AND_RETURN_VAL( + mjs, MJS_BAD_ARGS_ERROR, false, "failed to fetch element button"); + GuiButtonType btn_type; + if(strcmp(btn_name, "left") == 0) { + btn_type = GuiButtonTypeLeft; + } else if(strcmp(btn_name, "center") == 0) { + btn_type = GuiButtonTypeCenter; + } else if(strcmp(btn_name, "right") == 0) { + btn_type = GuiButtonTypeRight; + } else { + JS_ERROR_AND_RETURN_VAL(mjs, MJS_BAD_ARGS_ERROR, false, "incorrect button type"); + } + mjs_val_t text; + DESTRUCTURE_OR_RETURN(mjs, child_obj, text, &text); + widget_add_button_element( + widget, + btn_type, + mjs_get_string(mjs, &text, NULL), + (ButtonCallback)js_widget_button_callback, + context); + + } else if(strcmp(element_type, "icon") == 0) { + int32_t x, y; + DESTRUCTURE_OR_RETURN(mjs, child_obj, position, &x, &y); + mjs_val_t icon_data_in = mjs_get(mjs, child_obj, "iconData", ~0); + if(!mjs_is_foreign(icon_data_in)) + JS_ERROR_AND_RETURN_VAL( + mjs, MJS_BAD_ARGS_ERROR, false, "failed to fetch element iconData"); + const Icon* icon = mjs_get_ptr(mjs, icon_data_in); + widget_add_icon_element(widget, x, y, icon); + + } else if(strcmp(element_type, "frame") == 0) { + int32_t x, y, w, h; + DESTRUCTURE_OR_RETURN(mjs, child_obj, position, &x, &y); + DESTRUCTURE_OR_RETURN(mjs, child_obj, size, &w, &h); + mjs_val_t radius_in = mjs_get(mjs, child_obj, "radius", ~0); + if(!mjs_is_number(radius_in)) + JS_ERROR_AND_RETURN_VAL( + mjs, MJS_BAD_ARGS_ERROR, false, "failed to fetch element radius"); + int32_t radius = mjs_get_int32(mjs, radius_in); + widget_add_frame_element(widget, x, y, w, h, radius); + } + + return true; +} + +static void js_widget_reset_children(Widget* widget, void* state) { + UNUSED(state); + widget_reset(widget); +} + +static mjs_val_t js_widget_button_event_transformer( + struct mjs* mjs, + FuriMessageQueue* queue, + JsWidgetCtx* context) { + UNUSED(context); + GuiButtonType btn_type; + furi_check(furi_message_queue_get(queue, &btn_type, 0) == FuriStatusOk); + const char* btn_name; + if(btn_type == GuiButtonTypeLeft) { + btn_name = "left"; + } else if(btn_type == GuiButtonTypeCenter) { + btn_name = "center"; + } else if(btn_type == GuiButtonTypeRight) { + btn_name = "right"; + } else { + furi_crash(); + } + return mjs_mk_string(mjs, btn_name, ~0, false); +} + +static void* js_widget_custom_make(struct mjs* mjs, Widget* widget, mjs_val_t view_obj) { + UNUSED(widget); + JsWidgetCtx* context = malloc(sizeof(JsWidgetCtx)); + context->queue = furi_message_queue_alloc(QUEUE_LEN, sizeof(GuiButtonType)); + context->contract = (JsEventLoopContract){ + .magic = JsForeignMagic_JsEventLoopContract, + .object_type = JsEventLoopObjectTypeQueue, + .object = context->queue, + .non_timer = + { + .event = FuriEventLoopEventIn, + .transformer = (JsEventLoopTransformer)js_widget_button_event_transformer, + }, + }; + mjs_set(mjs, view_obj, "button", ~0, mjs_mk_foreign(mjs, &context->contract)); + return context; +} + +static void js_widget_custom_destroy(Widget* widget, JsWidgetCtx* context, FuriEventLoop* loop) { + UNUSED(widget); + furi_event_loop_maybe_unsubscribe(loop, context->queue); + furi_message_queue_free(context->queue); + free(context); +} + +static const JsViewDescriptor view_descriptor = { + .alloc = (JsViewAlloc)widget_alloc, + .free = (JsViewFree)widget_free, + .get_view = (JsViewGetView)widget_get_view, + .custom_make = (JsViewCustomMake)js_widget_custom_make, + .custom_destroy = (JsViewCustomDestroy)js_widget_custom_destroy, + .add_child = (JsViewAddChild)js_widget_add_child, + .reset_children = (JsViewResetChildren)js_widget_reset_children, + .prop_cnt = 0, + .props = {}, +}; +JS_GUI_VIEW_DEF(widget, &view_descriptor); diff --git a/applications/system/js_app/packages/fz-sdk/gpio/index.d.ts b/applications/system/js_app/packages/fz-sdk/gpio/index.d.ts index b484ebbf6..cd5ce2b60 100644 --- a/applications/system/js_app/packages/fz-sdk/gpio/index.d.ts +++ b/applications/system/js_app/packages/fz-sdk/gpio/index.d.ts @@ -75,6 +75,34 @@ export interface Pin { * @version Added in JS SDK 0.1 */ interrupt(): Contract; + /** + * Determines whether this pin supports PWM. If `false`, all other + * PWM-related methods on this pin will throw an error when called. + * @note On Flipper Zero only pins PA4 and PA7 support PWM + * @version Added in JS SDK 0.2, extra feature `"gpio-pwm"` + */ + isPwmSupported(): boolean; + /** + * Sets PWM parameters and starts the PWM. Configures the pin with + * `{ direction: "out", outMode: "push_pull" }`. Throws an error if PWM is + * not supported on this pin. + * @param freq Frequency in Hz + * @param duty Duty cycle in % + * @version Added in JS SDK 0.2, extra feature `"gpio-pwm"` + */ + pwmWrite(freq: number, duty: number): void; + /** + * Determines whether PWM is running. Throws an error if PWM is not + * supported on this pin. + * @version Added in JS SDK 0.2, extra feature `"gpio-pwm"` + */ + isPwmRunning(): boolean; + /** + * Stops PWM. Does not restore previous pin configuration. Throws an error + * if PWM is not supported on this pin. + * @version Added in JS SDK 0.2, extra feature `"gpio-pwm"` + */ + pwmStop(): void; } /** diff --git a/applications/system/js_app/packages/fz-sdk/gui/byte_input.d.ts b/applications/system/js_app/packages/fz-sdk/gui/byte_input.d.ts index 5556e7fbb..7080ad3ae 100644 --- a/applications/system/js_app/packages/fz-sdk/gui/byte_input.d.ts +++ b/applications/system/js_app/packages/fz-sdk/gui/byte_input.d.ts @@ -33,9 +33,10 @@ type Props = { length: number, defaultData: Uint8Array | ArrayBuffer, } -declare class ByteInput extends View { +type Child = never; +declare class ByteInput extends View { input: Contract; } -declare class ByteInputFactory extends ViewFactory { } +declare class ByteInputFactory extends ViewFactory { } declare const factory: ByteInputFactory; export = factory; diff --git a/applications/system/js_app/packages/fz-sdk/gui/dialog.d.ts b/applications/system/js_app/packages/fz-sdk/gui/dialog.d.ts index 9bd0c3966..2fffcb873 100644 --- a/applications/system/js_app/packages/fz-sdk/gui/dialog.d.ts +++ b/applications/system/js_app/packages/fz-sdk/gui/dialog.d.ts @@ -37,9 +37,10 @@ type Props = { center: string, right: string, } -declare class Dialog extends View { +type Child = never; +declare class Dialog extends View { input: Contract<"left" | "center" | "right">; } -declare class DialogFactory extends ViewFactory { } +declare class DialogFactory extends ViewFactory { } declare const factory: DialogFactory; export = factory; diff --git a/applications/system/js_app/packages/fz-sdk/gui/empty_screen.d.ts b/applications/system/js_app/packages/fz-sdk/gui/empty_screen.d.ts index 49e591426..6a848bd03 100644 --- a/applications/system/js_app/packages/fz-sdk/gui/empty_screen.d.ts +++ b/applications/system/js_app/packages/fz-sdk/gui/empty_screen.d.ts @@ -26,7 +26,8 @@ import type { View, ViewFactory } from "."; type Props = {}; -declare class EmptyScreen extends View { } -declare class EmptyScreenFactory extends ViewFactory { } +type Child = never; +declare class EmptyScreen extends View { } +declare class EmptyScreenFactory extends ViewFactory { } declare const factory: EmptyScreenFactory; export = factory; diff --git a/applications/system/js_app/packages/fz-sdk/gui/icon.d.ts b/applications/system/js_app/packages/fz-sdk/gui/icon.d.ts new file mode 100644 index 000000000..577e1e6a9 --- /dev/null +++ b/applications/system/js_app/packages/fz-sdk/gui/icon.d.ts @@ -0,0 +1,11 @@ +export type BuiltinIcon = "DolphinWait_59x54" | "js_script_10px"; + +export type IconData = symbol & { "__tag__": "icon" }; +// introducing a nominal type in a hacky way; the `__tag__` property doesn't really exist. + +/** + * Gets a built-in firmware icon for use in GUI + * @param icon Name of the icon + * @version Added in JS SDK 0.2, extra feature `"gui-widget"` + */ +export declare function getBuiltin(icon: BuiltinIcon): IconData; diff --git a/applications/system/js_app/packages/fz-sdk/gui/index.d.ts b/applications/system/js_app/packages/fz-sdk/gui/index.d.ts index 93a6846c2..969b6934e 100644 --- a/applications/system/js_app/packages/fz-sdk/gui/index.d.ts +++ b/applications/system/js_app/packages/fz-sdk/gui/index.d.ts @@ -26,23 +26,23 @@ * assumes control over the entire viewport and all input events. Different * types of views are available (not all of which are unfortunately currently * implemented in JS): - * | View | Has JS adapter? | - * |----------------------|------------------| - * | `button_menu` | ❌ | - * | `button_panel` | ❌ | - * | `byte_input` | ✅ | - * | `dialog_ex` | ✅ (as `dialog`) | - * | `empty_screen` | ✅ | - * | `file_browser` | ❌ | - * | `loading` | ✅ | - * | `menu` | ❌ | - * | `number_input` | ❌ | - * | `popup` | ❌ | - * | `submenu` | ✅ | - * | `text_box` | ✅ | - * | `text_input` | ✅ | - * | `variable_item_list` | ❌ | - * | `widget` | ❌ | + * | View | Has JS adapter? | + * |----------------------|-----------------------| + * | `button_menu` | ❌ | + * | `button_panel` | ❌ | + * | `byte_input` | ✅ | + * | `dialog_ex` | ✅ (as `dialog`) | + * | `empty_screen` | ✅ | + * | `file_browser` | ✅ (as `file_picker`) | + * | `loading` | ✅ | + * | `menu` | ❌ | + * | `number_input` | ❌ | + * | `popup` | ❌ | + * | `submenu` | ✅ | + * | `text_box` | ✅ | + * | `text_input` | ✅ | + * | `variable_item_list` | ❌ | + * | `widget` | ✅ | * * In JS, each view has its own set of properties (or just "props"). The * programmer can manipulate these properties in two ways: @@ -121,7 +121,7 @@ import type { Contract } from "../event_loop"; type Properties = { [K: string]: any }; -export declare class View { +export declare class View { /** * Assign value to property by name * @param property Name of the property @@ -129,9 +129,26 @@ export declare class View { * @version Added in JS SDK 0.1 */ set

(property: P, value: Props[P]): void; + /** + * Adds a child to the View + * @param child Child to add + * @version Added in JS SDK 0.2, extra feature `"gui-widget"` + */ + addChild(child: C): void; + /** + * Removes all children from the View + * @version Added in JS SDK 0.2, extra feature `"gui-widget"` + */ + resetChildren(): void; + /** + * Removes all previous children from the View and assigns new children + * @param children The list of children to assign + * @version Added in JS SDK 0.2, extra feature `"gui-widget"` + */ + setChildren(children: Child[]): void; } -export declare class ViewFactory> { +export declare class ViewFactory> { /** * Create view instance with default values, can be changed later with set() * @version Added in JS SDK 0.1 @@ -140,9 +157,10 @@ export declare class ViewFactory /** * Create view instance with custom values, can be changed later with set() * @param initial Dictionary of property names to values - * @version Added in JS SDK 0.1 + * @param children Optional list of children to add to the view + * @version Added in JS SDK 0.1; amended in JS SDK 0.2, extra feature `"gui-widget"` */ - makeWith(initial: Partial): V; + makeWith(initial: Partial, children?: Child[]): V; } /** @@ -163,7 +181,7 @@ declare class ViewDispatcher { * View object currently shown * @version Added in JS SDK 0.1 */ - currentView: View; + currentView: View; /** * Sends a number to the custom event handler * @param event number to send @@ -175,7 +193,7 @@ declare class ViewDispatcher { * @param assoc View-ViewDispatcher association as returned by `add` * @version Added in JS SDK 0.1 */ - switchTo(assoc: View): void; + switchTo(assoc: View): void; /** * Sends this ViewDispatcher to the front or back, above or below all other * GUI viewports diff --git a/applications/system/js_app/packages/fz-sdk/gui/loading.d.ts b/applications/system/js_app/packages/fz-sdk/gui/loading.d.ts index b8b10c43a..d636f21ca 100644 --- a/applications/system/js_app/packages/fz-sdk/gui/loading.d.ts +++ b/applications/system/js_app/packages/fz-sdk/gui/loading.d.ts @@ -27,7 +27,8 @@ import type { View, ViewFactory } from "."; type Props = {}; -declare class Loading extends View { } -declare class LoadingFactory extends ViewFactory { } +type Child = never; +declare class Loading extends View { } +declare class LoadingFactory extends ViewFactory { } declare const factory: LoadingFactory; export = factory; diff --git a/applications/system/js_app/packages/fz-sdk/gui/submenu.d.ts b/applications/system/js_app/packages/fz-sdk/gui/submenu.d.ts index 31e08aab8..e73856bee 100644 --- a/applications/system/js_app/packages/fz-sdk/gui/submenu.d.ts +++ b/applications/system/js_app/packages/fz-sdk/gui/submenu.d.ts @@ -31,9 +31,10 @@ type Props = { header: string, items: string[], }; -declare class Submenu extends View { +type Child = never; +declare class Submenu extends View { chosen: Contract; } -declare class SubmenuFactory extends ViewFactory { } +declare class SubmenuFactory extends ViewFactory { } declare const factory: SubmenuFactory; export = factory; diff --git a/applications/system/js_app/packages/fz-sdk/gui/text_box.d.ts b/applications/system/js_app/packages/fz-sdk/gui/text_box.d.ts index a46ec73fa..32003bd95 100644 --- a/applications/system/js_app/packages/fz-sdk/gui/text_box.d.ts +++ b/applications/system/js_app/packages/fz-sdk/gui/text_box.d.ts @@ -33,9 +33,10 @@ type Props = { font: "text" | "hex", focus: "start" | "end", } -declare class TextBox extends View { +type Child = never; +declare class TextBox extends View { chosen: Contract; } -declare class TextBoxFactory extends ViewFactory { } +declare class TextBoxFactory extends ViewFactory { } declare const factory: TextBoxFactory; export = factory; diff --git a/applications/system/js_app/packages/fz-sdk/gui/text_input.d.ts b/applications/system/js_app/packages/fz-sdk/gui/text_input.d.ts index 5d64b038b..9d0d180ba 100644 --- a/applications/system/js_app/packages/fz-sdk/gui/text_input.d.ts +++ b/applications/system/js_app/packages/fz-sdk/gui/text_input.d.ts @@ -37,9 +37,10 @@ type Props = { defaultText: string, defaultTextClear: boolean, } -declare class TextInput extends View { +type Child = never; +declare class TextInput extends View { input: Contract; } -declare class TextInputFactory extends ViewFactory { } +declare class TextInputFactory extends ViewFactory { } declare const factory: TextInputFactory; export = factory; diff --git a/applications/system/js_app/packages/fz-sdk/gui/widget.d.ts b/applications/system/js_app/packages/fz-sdk/gui/widget.d.ts new file mode 100644 index 000000000..b37af8e3c --- /dev/null +++ b/applications/system/js_app/packages/fz-sdk/gui/widget.d.ts @@ -0,0 +1,66 @@ +/** + * Displays a combination of custom elements on one screen. + * + * Sample screenshot of the view + * + * ```js + * let eventLoop = require("event_loop"); + * let gui = require("gui"); + * let emptyView = require("gui/widget"); + * ``` + * + * This module depends on the `gui` module, which in turn depends on the + * `event_loop` module, so they _must_ be imported in this order. It is also + * recommended to conceptualize these modules first before using this one. + * + * # Example + * For an example refer to the GUI example. + * + * # View props + * This view does not have any props. + * + * # Children + * This view has the elements as its children. + * + * @version Added in JS SDK 0.2, extra feature `"gui-widget"` + * @module + */ + +import type { View, ViewFactory } from "."; +import type { IconData } from "./icon"; +import type { Contract } from "../event_loop"; + +type Position = { x: number, y: number }; +type Size = { w: number, h: number }; +type Alignment = { align: `${"t" | "c" | "b"}${"l" | "m" | "r"}` }; +type Font = { font: "primary" | "secondary" | "keyboard" | "big_numbers" }; +type Text = { text: string }; + +type StringMultilineElement = { element: "string_multiline" } & Position & Alignment & Font & Text; +type StringElement = { element: "string" } & Position & Alignment & Font & Text; +type TextBoxElement = { element: "text_box", stripToDots: boolean } & Position & Size & Alignment & Text; +type TextScrollElement = { element: "text_scroll" } & Position & Size & Text; +type ButtonElement = { element: "button", button: "left" | "center" | "right" } & Text; +type IconElement = { element: "icon", iconData: IconData } & Position; +type FrameElement = { element: "frame", radius: number } & Position & Size; + +type Element = StringMultilineElement + | StringElement + | TextBoxElement + | TextScrollElement + | ButtonElement + | IconElement + | FrameElement; + +type Props = {}; +type Child = Element; +declare class Widget extends View { + /** + * Event source for buttons. Only gets fired if there's a corresponding + * button element. + */ + button: Contract<"left" | "center" | "right">; +} +declare class WidgetFactory extends ViewFactory { } +declare const factory: WidgetFactory; +export = factory; diff --git a/applications/system/js_app/packages/fz-sdk/package.json b/applications/system/js_app/packages/fz-sdk/package.json index f500fae2b..523845738 100644 --- a/applications/system/js_app/packages/fz-sdk/package.json +++ b/applications/system/js_app/packages/fz-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@flipperdevices/fz-sdk", - "version": "0.1.3", + "version": "0.2.0", "description": "Type declarations and documentation for native JS modules available on Flipper Zero", "keywords": [ "flipper", diff --git a/documentation/images/widget.png b/documentation/images/widget.png new file mode 100644 index 0000000000000000000000000000000000000000..f4dd1ed5beec5c28242adedc09808bc9c650e29a GIT binary patch literal 2390 zcmbVOeN+=y7Jo5TgssNYU8_h*-If*?&MF#kfe>*0LckTU#7Gd(r4kLLSlRHA6cYEW zJ?mwjE%aFxO9 z{oHG7zhVhT5IN>Gkc_Obc z`!yg~NaSrnrJotLR$x9IQFuMiP#TtHDW=h$Va&PODhhz6%n{~uM9i7cp9p)_b*>*; zr9QdlHRX5|Xs=nwQ(K_<1Dj8ybG^k_Ln;`z^e8UuH2iHknpdLNaTek5G*z2xj>M1B z6h`;I=_cu>^MRXlr3H86pJ-&g^Zs#Kj?5NgqYw0Ax81yGdzE@)zmDPJlocc46y+n> zFP(D4VrFoUY0S6pMQbRkgHeYIJ(#^Ni$u09Jba{AartEhd?>A%K z18EyxI#}3_f`gR2oIG8k4*p(zqJ+4l-f5(^q-xF~@(Vs16D=EKp7;!By`_k~EI%Ie zC4I;BTjVe!bs4C4n}{L!myTG0u5yQF((tWLA8J+vqLsN*9a45F3h(61zqJ`59){4f z(_M^nX2$dh3mNNg@yOhZ#8SPGxJR=y5yp)ctL3xB)#-VXr7=dr3)#c3G2y>vz(2e> zZQKP{ll2sxs$(DFyALtpW?AWbNVPv~I@2$rOIQ`^C)e~JV|duXUMgq13~KmlWaqss z%*M}bKpT=8AGgv)ItS;eS2qa*Fy#bcJcX=x1ScFvr^=XUr3H~c$@q{^j_1ASNglUW zyLDz2!{!%d@-2Xz#a;OW(w+`c$QS89s4Fq}BSl^z@fX=YPeV>|$!}Pb@@Bg9F5(E2 zSWaW$G}u9qc8blsTCXS6BooH2DM;E<(edt`U=d>rrrE8stnC8S7B6n2LajIP@3fOu6+vH|@8~OT4~gBPk;mIvgG|WjPbJfIeGiUK7!q3CAC7(?@aaCklJ)L{2y6CA zk~H)+`XI-msf&Ka_TsrR&9$*MnZx;`omJ#>1q)&f#-)hQDiXw>*)l9Ktot=g?)$nv z(xWS^is@~C;Qs=^dBS&%`Yul0&GQsCN_WZrV_qop(G)7hA$-0`^RQmVh-#(!X~d0R?K0J~Ie+ z^ZARXQlw|*6{~3FnYmG!WefdE?{57o? z^6GR6+44?TV{+K=ux4va#1~XHJ3TQ&$~1MbYniq+=@eS4$~B2qg;rI^Dh<+F3#2<} z;=ozC@8Z5IbhM$TDCiwQDaJmma}ac}Gcc7E&ES5TxUO?#*OOojI`t z=Bjc3Yo5YfHee12=wS|D7I*WV5-PS`v9Ig&i6ys7w2QddRA zm276SL{M|Hv8O`S*pSR}CFguB*;TLFZK}rLjVGMENrn1{5tMJrEGfKjn6?<_jouU5 zu&uyd%IfF4B*z$|Gc^uK + +```js +let eventLoop = require("event_loop"); +let gui = require("gui"); +let widgetView = require("gui/widget"); +``` + +This module depends on the `gui` module, which in turn depends on the +`event_loop` module, so they _must_ be imported in this order. It is also +recommended to conceptualize these modules first before using this one. + +# Example +For an example refer to the `gui.js` example script. + +# View props +This view does not have any props. + +# Children +This view has the elements as its children. diff --git a/lib/mjs/mjs_exec.c b/lib/mjs/mjs_exec.c index 8fdb2d7e5..273c38a34 100644 --- a/lib/mjs/mjs_exec.c +++ b/lib/mjs/mjs_exec.c @@ -584,7 +584,8 @@ static void mjs_apply_(struct mjs* mjs) { if(mjs_is_array(v)) { nargs = mjs_array_length(mjs, v); args = calloc(nargs, sizeof(args[0])); - for(i = 0; i < nargs; i++) args[i] = mjs_array_get(mjs, v, i); + for(i = 0; i < nargs; i++) + args[i] = mjs_array_get(mjs, v, i); } mjs_apply(mjs, &res, func, mjs_arg(mjs, 0), nargs, args); free(args); diff --git a/targets/f18/furi_hal/furi_hal_resources.h b/targets/f18/furi_hal/furi_hal_resources.h index 9a0d04cb6..23a88c215 100644 --- a/targets/f18/furi_hal/furi_hal_resources.h +++ b/targets/f18/furi_hal/furi_hal_resources.h @@ -2,6 +2,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -40,6 +41,7 @@ typedef struct { const GpioPin* pin; const char* name; const FuriHalAdcChannel channel; + const FuriHalPwmOutputId pwm_output; const uint8_t number; const bool debug; } GpioPinRecord; diff --git a/targets/f7/furi_hal/furi_hal_pwm.h b/targets/f7/furi_hal/furi_hal_pwm.h index 16acca05e..30a5467d2 100644 --- a/targets/f7/furi_hal/furi_hal_pwm.h +++ b/targets/f7/furi_hal/furi_hal_pwm.h @@ -12,6 +12,7 @@ extern "C" { #include typedef enum { + FuriHalPwmOutputIdNone, FuriHalPwmOutputIdTim1PA7, FuriHalPwmOutputIdLptim2PA4, } FuriHalPwmOutputId; diff --git a/targets/f7/furi_hal/furi_hal_resources.c b/targets/f7/furi_hal/furi_hal_resources.c index 123ebc420..a6ba0b083 100644 --- a/targets/f7/furi_hal/furi_hal_resources.c +++ b/targets/f7/furi_hal/furi_hal_resources.c @@ -73,6 +73,7 @@ const GpioPinRecord gpio_pins[] = { {.pin = &gpio_ext_pa7, .name = "PA7", .channel = FuriHalAdcChannel12, + .pwm_output = FuriHalPwmOutputIdTim1PA7, .number = 2, .debug = false}, {.pin = &gpio_ext_pa6, @@ -83,6 +84,7 @@ const GpioPinRecord gpio_pins[] = { {.pin = &gpio_ext_pa4, .name = "PA4", .channel = FuriHalAdcChannel9, + .pwm_output = FuriHalPwmOutputIdLptim2PA4, .number = 4, .debug = false}, {.pin = &gpio_ext_pb3, diff --git a/targets/f7/furi_hal/furi_hal_resources.h b/targets/f7/furi_hal/furi_hal_resources.h index ec8794cc1..3e8501b86 100644 --- a/targets/f7/furi_hal/furi_hal_resources.h +++ b/targets/f7/furi_hal/furi_hal_resources.h @@ -2,6 +2,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -40,6 +41,7 @@ typedef struct { const GpioPin* pin; const char* name; const FuriHalAdcChannel channel; + const FuriHalPwmOutputId pwm_output; const uint8_t number; const bool debug; } GpioPinRecord; From de85cc7a8e47b4ecb8e6f8754d891b1f07cddb78 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Thu, 13 Feb 2025 13:07:03 +0300 Subject: [PATCH 10/14] ST25TB poller mode check (#4084) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/nfc/protocols/st25tb/st25tb_poller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nfc/protocols/st25tb/st25tb_poller.c b/lib/nfc/protocols/st25tb/st25tb_poller.c index fd6dc4f09..674a439cd 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller.c +++ b/lib/nfc/protocols/st25tb/st25tb_poller.c @@ -88,7 +88,7 @@ static NfcCommand st25tb_poller_request_mode_handler(St25tbPoller* instance) { St25tbPollerEventDataModeRequest* mode_request_data = &instance->st25tb_event_data.mode_request; - furi_assert(mode_request_data->mode < St25tbPollerModeNum); + furi_check(mode_request_data->mode < St25tbPollerModeNum); if(mode_request_data->mode == St25tbPollerModeRead) { instance->state = St25tbPollerStateRead; From 59fe896ce8bcec4e5255f242cb6e468c926462b5 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Thu, 13 Feb 2025 03:31:56 -0700 Subject: [PATCH 11/14] nfc: Enable MFUL sync poller to be provided with passwords (#4050) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: Enable MFUL sync poller to be provided with passwords * Sync targret api versions Co-authored-by: あく --- .../debug/unit_tests/tests/nfc/nfc_test.c | 8 +++---- .../mf_ultralight/mf_ultralight_poller_sync.c | 24 +++++++++++++------ .../mf_ultralight/mf_ultralight_poller_sync.h | 6 ++++- targets/f18/api_symbols.csv | 2 +- targets/f7/api_symbols.csv | 4 ++-- 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/applications/debug/unit_tests/tests/nfc/nfc_test.c b/applications/debug/unit_tests/tests/nfc/nfc_test.c index 4ba934b6d..e028b8041 100644 --- a/applications/debug/unit_tests/tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/tests/nfc/nfc_test.c @@ -262,7 +262,7 @@ static void mf_ultralight_reader_test(const char* path) { nfc_listener_start(mfu_listener, NULL, NULL); MfUltralightData* mfu_data = mf_ultralight_alloc(); - MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data, NULL); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); nfc_listener_stop(mfu_listener); @@ -315,7 +315,7 @@ MU_TEST(ntag_213_locked_reader) { nfc_listener_start(mfu_listener, NULL, NULL); MfUltralightData* mfu_data = mf_ultralight_alloc(); - MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data, NULL); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); nfc_listener_stop(mfu_listener); @@ -353,7 +353,7 @@ static void mf_ultralight_write(void) { MfUltralightData* mfu_data = mf_ultralight_alloc(); // Initial read - MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data, NULL); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); mu_assert( @@ -371,7 +371,7 @@ static void mf_ultralight_write(void) { } // Verification read - error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + error = mf_ultralight_poller_sync_read_card(poller, mfu_data, NULL); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); nfc_listener_stop(mfu_listener); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.c index 9958dc50d..252c46399 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.c @@ -23,6 +23,7 @@ typedef struct { FuriThreadId thread_id; MfUltralightError error; MfUltralightPollerContextData data; + const MfUltralightPollerAuthContext* auth_context; } MfUltralightPollerContext; typedef MfUltralightError (*MfUltralightPollerCmdHandler)( @@ -250,12 +251,17 @@ static NfcCommand mf_ultralight_poller_read_callback(NfcGenericEvent event, void poller_context->error = mfu_event->data->error; command = NfcCommandStop; } else if(mfu_event->type == MfUltralightPollerEventTypeAuthRequest) { - mfu_event->data->auth_context.skip_auth = true; - if(mf_ultralight_support_feature( - mfu_poller->feature_set, MfUltralightFeatureSupportAuthenticate)) { - mfu_event->data->auth_context.skip_auth = false; - memset( - mfu_poller->auth_context.tdes_key.data, 0x00, MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE); + if(poller_context->auth_context != NULL) { + mfu_event->data->auth_context = *poller_context->auth_context; + } else { + mfu_event->data->auth_context.skip_auth = true; + if(mfu_poller->data->type == MfUltralightTypeMfulC) { + mfu_event->data->auth_context.skip_auth = false; + memset( + mfu_poller->auth_context.tdes_key.data, + 0x00, + MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE); + } } } @@ -266,13 +272,17 @@ static NfcCommand mf_ultralight_poller_read_callback(NfcGenericEvent event, void return command; } -MfUltralightError mf_ultralight_poller_sync_read_card(Nfc* nfc, MfUltralightData* data) { +MfUltralightError mf_ultralight_poller_sync_read_card( + Nfc* nfc, + MfUltralightData* data, + const MfUltralightPollerAuthContext* auth_context) { furi_check(nfc); furi_check(data); MfUltralightPollerContext poller_context = {}; poller_context.thread_id = furi_thread_get_current_id(); poller_context.data.data = mf_ultralight_alloc(); + poller_context.auth_context = auth_context; NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfUltralight); nfc_poller_start(poller, mf_ultralight_poller_read_callback, &poller_context); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h index ac585aad7..3f63203a7 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h @@ -1,6 +1,7 @@ #pragma once #include "mf_ultralight.h" +#include "mf_ultralight_poller.h" #include #ifdef __cplusplus @@ -27,7 +28,10 @@ MfUltralightError mf_ultralight_poller_sync_read_tearing_flag( uint8_t flag_num, MfUltralightTearingFlag* data); -MfUltralightError mf_ultralight_poller_sync_read_card(Nfc* nfc, MfUltralightData* data); +MfUltralightError mf_ultralight_poller_sync_read_card( + Nfc* nfc, + MfUltralightData* data, + const MfUltralightPollerAuthContext* auth_context); #ifdef __cplusplus } diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 56bfbc2e6..d158b4f68 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,79.3,, +Version,+,80.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 707acacff..2c3b696cb 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,79.3,, +Version,+,80.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -2681,7 +2681,7 @@ Function,+,mf_ultralight_poller_read_page_from_sector,MfUltralightError,"MfUltra Function,+,mf_ultralight_poller_read_signature,MfUltralightError,"MfUltralightPoller*, MfUltralightSignature*" Function,+,mf_ultralight_poller_read_tearing_flag,MfUltralightError,"MfUltralightPoller*, uint8_t, MfUltralightTearingFlag*" Function,+,mf_ultralight_poller_read_version,MfUltralightError,"MfUltralightPoller*, MfUltralightVersion*" -Function,+,mf_ultralight_poller_sync_read_card,MfUltralightError,"Nfc*, MfUltralightData*" +Function,+,mf_ultralight_poller_sync_read_card,MfUltralightError,"Nfc*, MfUltralightData*, const MfUltralightPollerAuthContext*" Function,+,mf_ultralight_poller_sync_read_counter,MfUltralightError,"Nfc*, uint8_t, MfUltralightCounter*" Function,+,mf_ultralight_poller_sync_read_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" Function,+,mf_ultralight_poller_sync_read_signature,MfUltralightError,"Nfc*, MfUltralightSignature*" From 429c0dd387e82fa43a9c094e158ca3a3bb8d7aff Mon Sep 17 00:00:00 2001 From: Demae <56660883+Demae@users.noreply.github.com> Date: Thu, 13 Feb 2025 21:19:53 +1030 Subject: [PATCH 12/14] Added naming for DESFire cards + fix MF3ICD40 cards unable to be read (#4058) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed MF3ICD40 DESFire cards soft-locking NFC application due to read free memory being an unsupported function, added naming for DESFire cards * NFC: slightly more granular desfire card type resolution Co-authored-by: あく --- lib/nfc/protocols/mf_desfire/mf_desfire.c | 122 +++++++++++++++++- lib/nfc/protocols/mf_desfire/mf_desfire.h | 24 ++++ .../protocols/mf_desfire/mf_desfire_poller.c | 5 +- .../mf_desfire/mf_desfire_poller_i.c | 2 + 4 files changed, 148 insertions(+), 5 deletions(-) diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index 4d54a2c0e..42ad4634b 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -4,6 +4,46 @@ #define MF_DESFIRE_PROTOCOL_NAME "Mifare DESFire" +#define MF_DESFIRE_HW_MINOR_TYPE (0x00) +#define MF_DESFIRE_HW_MINOR_TYPE_MF3ICD40 (0x02) + +#define MF_DESFIRE_HW_MAJOR_TYPE_EV1 (0x01) +#define MF_DESFIRE_HW_MAJOR_TYPE_EV2 (0x12) +#define MF_DESFIRE_HW_MAJOR_TYPE_EV2_XL (0x22) +#define MF_DESFIRE_HW_MAJOR_TYPE_EV3 (0x33) +#define MF_DESFIRE_HW_MAJOR_TYPE_MF3ICD40 (0x00) + +#define MF_DESFIRE_STORAGE_SIZE_2K (0x16) +#define MF_DESFIRE_STORAGE_SIZE_4K (0x18) +#define MF_DESFIRE_STORAGE_SIZE_8K (0x1A) +#define MF_DESFIRE_STORAGE_SIZE_16K (0x1C) +#define MF_DESFIRE_STORAGE_SIZE_32K (0x1E) +#define MF_DESFIRE_STORAGE_SIZE_MF3ICD40 (0xFF) +#define MF_DESFIRE_STORAGE_SIZE_UNKNOWN (0xFF) + +#define MF_DESFIRE_TEST_TYPE_MF3ICD40(major, minor, storage) \ + (((major) == MF_DESFIRE_HW_MAJOR_TYPE_MF3ICD40) && \ + ((minor) == MF_DESFIRE_HW_MINOR_TYPE_MF3ICD40) && \ + ((storage) == MF_DESFIRE_STORAGE_SIZE_MF3ICD40)) + +static const char* mf_desfire_type_strings[] = { + [MfDesfireTypeMF3ICD40] = "(MF3ICD40)", + [MfDesfireTypeEV1] = "EV1", + [MfDesfireTypeEV2] = "EV2", + [MfDesfireTypeEV2XL] = "EV2 XL", + [MfDesfireTypeEV3] = "EV3", + [MfDesfireTypeUnknown] = "UNK", +}; + +static const char* mf_desfire_size_strings[] = { + [MfDesfireSize2k] = "2K", + [MfDesfireSize4k] = "4K", + [MfDesfireSize8k] = "8K", + [MfDesfireSize16k] = "16K", + [MfDesfireSize32k] = "32K", + [MfDesfireSizeUnknown] = "", +}; + const NfcDeviceBase nfc_device_mf_desfire = { .protocol_name = MF_DESFIRE_PROTOCOL_NAME, .alloc = (NfcDeviceAlloc)mf_desfire_alloc, @@ -26,7 +66,7 @@ MfDesfireData* mf_desfire_alloc(void) { data->master_key_versions = simple_array_alloc(&mf_desfire_key_version_array_config); data->application_ids = simple_array_alloc(&mf_desfire_app_id_array_config); data->applications = simple_array_alloc(&mf_desfire_application_array_config); - + data->device_name = furi_string_alloc(); return data; } @@ -38,6 +78,7 @@ void mf_desfire_free(MfDesfireData* data) { simple_array_free(data->application_ids); simple_array_free(data->master_key_versions); iso14443_4a_free(data->iso14443_4a_data); + furi_string_free(data->device_name); free(data); } @@ -228,10 +269,83 @@ bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other) simple_array_is_equal(data->applications, other->applications); } +static MfDesfireType mf_desfire_get_type_from_version(const MfDesfireVersion* const version) { + MfDesfireType type = MfDesfireTypeUnknown; + + switch(version->hw_major) { + case MF_DESFIRE_HW_MAJOR_TYPE_EV1: + type = MfDesfireTypeEV1; + break; + case MF_DESFIRE_HW_MAJOR_TYPE_EV2: + type = MfDesfireTypeEV2; + break; + case MF_DESFIRE_HW_MAJOR_TYPE_EV2_XL: + type = MfDesfireTypeEV2XL; + break; + case MF_DESFIRE_HW_MAJOR_TYPE_EV3: + type = MfDesfireTypeEV3; + break; + default: + if(MF_DESFIRE_TEST_TYPE_MF3ICD40(version->hw_major, version->hw_minor, version->hw_storage)) + type = MfDesfireTypeMF3ICD40; + break; + } + + return type; +} + +static MfDesfireSize mf_desfire_get_size_from_version(const MfDesfireVersion* const version) { + MfDesfireSize size = MfDesfireSizeUnknown; + + switch(version->hw_storage) { + case MF_DESFIRE_STORAGE_SIZE_2K: + size = MfDesfireSize2k; + break; + case MF_DESFIRE_STORAGE_SIZE_4K: + size = MfDesfireSize4k; + break; + case MF_DESFIRE_STORAGE_SIZE_8K: + size = MfDesfireSize8k; + break; + case MF_DESFIRE_STORAGE_SIZE_16K: + size = MfDesfireSize16k; + break; + case MF_DESFIRE_STORAGE_SIZE_32K: + size = MfDesfireSize32k; + break; + default: + if(MF_DESFIRE_TEST_TYPE_MF3ICD40(version->hw_major, version->hw_minor, version->hw_storage)) + size = MfDesfireSize4k; + break; + } + + return size; +} + const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcDeviceNameType name_type) { - UNUSED(data); - UNUSED(name_type); - return MF_DESFIRE_PROTOCOL_NAME; + furi_check(data); + + const MfDesfireType type = mf_desfire_get_type_from_version(&data->version); + const MfDesfireSize size = mf_desfire_get_size_from_version(&data->version); + + if(type == MfDesfireTypeUnknown) { + furi_string_printf(data->device_name, "Unknown %s", MF_DESFIRE_PROTOCOL_NAME); + } else if(name_type == NfcDeviceNameTypeFull) { + furi_string_printf( + data->device_name, + "%s %s %s", + MF_DESFIRE_PROTOCOL_NAME, + mf_desfire_type_strings[type], + mf_desfire_size_strings[size]); + } else { + furi_string_printf( + data->device_name, + "%s %s", + mf_desfire_type_strings[type], + mf_desfire_size_strings[size]); + } + + return furi_string_get_cstr(data->device_name); } const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len) { diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index dd2009276..fb50008db 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -29,6 +29,28 @@ extern "C" { #define MF_DESFIRE_APP_ID_SIZE (3) #define MF_DESFIRE_VALUE_SIZE (4) +typedef enum { + MfDesfireTypeMF3ICD40, + MfDesfireTypeEV1, + MfDesfireTypeEV2, + MfDesfireTypeEV2XL, + MfDesfireTypeEV3, + + MfDesfireTypeUnknown, + MfDesfireTypeNum, +} MfDesfireType; + +typedef enum { + MfDesfireSize2k, + MfDesfireSize4k, + MfDesfireSize8k, + MfDesfireSize16k, + MfDesfireSize32k, + + MfDesfireSizeUnknown, + MfDesfireSizeNum, +} MfDesfireSize; + typedef struct { uint8_t hw_vendor; uint8_t hw_type; @@ -131,6 +153,7 @@ typedef enum { MfDesfireErrorProtocol, MfDesfireErrorTimeout, MfDesfireErrorAuthentication, + MfDesfireErrorCommandNotSupported, } MfDesfireError; typedef struct { @@ -141,6 +164,7 @@ typedef struct { SimpleArray* master_key_versions; SimpleArray* application_ids; SimpleArray* applications; + FuriString* device_name; } MfDesfireData; extern const NfcDeviceBase nfc_device_mf_desfire; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index bd8ecfaee..45e5a27f9 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -82,9 +82,12 @@ static NfcCommand mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* in FURI_LOG_D(TAG, "Read free memory success"); instance->state = MfDesfirePollerStateReadMasterKeySettings; } else if(instance->error == MfDesfireErrorNotPresent) { - FURI_LOG_D(TAG, "Read free memoty is unsupported"); + FURI_LOG_D(TAG, "Read free memory is not present"); instance->state = MfDesfirePollerStateReadMasterKeySettings; command = NfcCommandReset; + } else if(instance->error == MfDesfireErrorCommandNotSupported) { + FURI_LOG_D(TAG, "Read free memory is unsupported"); + instance->state = MfDesfirePollerStateReadMasterKeySettings; } else { FURI_LOG_E(TAG, "Failed to read free memory"); iso14443_4a_poller_halt(instance->iso14443_4a_poller); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index 1dd6c50e1..6d8dfda16 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -25,6 +25,8 @@ MfDesfireError mf_desfire_process_status_code(uint8_t status_code) { return MfDesfireErrorNone; case MF_DESFIRE_STATUS_AUTHENTICATION_ERROR: return MfDesfireErrorAuthentication; + case MF_DESFIRE_STATUS_ILLEGAL_COMMAND_CODE: + return MfDesfireErrorCommandNotSupported; default: return MfDesfireErrorProtocol; } From 4895ae5d0d390b5a5cc0ff6e707e313d903b7d3a Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Mon, 17 Feb 2025 01:57:23 +0400 Subject: [PATCH 13/14] [FL-3957] EventLoop unsubscribe fix (#4109) * Fix memory leak during event loop unsubscription * Event better memory leak fix * unit test for the fix Co-authored-by: Georgii Surkov --- .../tests/furi/furi_event_loop_test.c | 49 +++++++++++++++++++ .../debug/unit_tests/tests/furi/furi_test.c | 6 +++ furi/core/event_loop.c | 29 +++++------ furi/core/event_loop_i.h | 4 +- 4 files changed, 72 insertions(+), 16 deletions(-) diff --git a/applications/debug/unit_tests/tests/furi/furi_event_loop_test.c b/applications/debug/unit_tests/tests/furi/furi_event_loop_test.c index 73f38ab77..08e0e8ad2 100644 --- a/applications/debug/unit_tests/tests/furi/furi_event_loop_test.c +++ b/applications/debug/unit_tests/tests/furi/furi_event_loop_test.c @@ -446,6 +446,55 @@ static int32_t test_furi_event_loop_consumer(void* p) { return 0; } +typedef struct { + FuriEventLoop* event_loop; + FuriSemaphore* semaphore; + size_t counter; +} SelfUnsubTestTimerContext; + +static void test_self_unsub_semaphore_callback(FuriEventLoopObject* object, void* context) { + furi_event_loop_unsubscribe(context, object); // shouldn't crash here +} + +static void test_self_unsub_timer_callback(void* arg) { + SelfUnsubTestTimerContext* context = arg; + + if(context->counter == 0) { + furi_semaphore_release(context->semaphore); + } else if(context->counter == 1) { + furi_event_loop_stop(context->event_loop); + } + + context->counter++; +} + +void test_furi_event_loop_self_unsubscribe(void) { + FuriEventLoop* event_loop = furi_event_loop_alloc(); + + FuriSemaphore* semaphore = furi_semaphore_alloc(1, 0); + furi_event_loop_subscribe_semaphore( + event_loop, + semaphore, + FuriEventLoopEventIn, + test_self_unsub_semaphore_callback, + event_loop); + + SelfUnsubTestTimerContext timer_context = { + .event_loop = event_loop, + .semaphore = semaphore, + .counter = 0, + }; + FuriEventLoopTimer* timer = furi_event_loop_timer_alloc( + event_loop, test_self_unsub_timer_callback, FuriEventLoopTimerTypePeriodic, &timer_context); + furi_event_loop_timer_start(timer, furi_ms_to_ticks(20)); + + furi_event_loop_run(event_loop); + + furi_event_loop_timer_free(timer); + furi_semaphore_free(semaphore); + furi_event_loop_free(event_loop); +} + void test_furi_event_loop(void) { TestFuriEventLoopData data = {}; diff --git a/applications/debug/unit_tests/tests/furi/furi_test.c b/applications/debug/unit_tests/tests/furi/furi_test.c index f23be37a9..03d49aa7e 100644 --- a/applications/debug/unit_tests/tests/furi/furi_test.c +++ b/applications/debug/unit_tests/tests/furi/furi_test.c @@ -8,6 +8,7 @@ void test_furi_concurrent_access(void); void test_furi_pubsub(void); void test_furi_memmgr(void); void test_furi_event_loop(void); +void test_furi_event_loop_self_unsubscribe(void); void test_errno_saving(void); void test_furi_primitives(void); void test_stdin(void); @@ -46,6 +47,10 @@ MU_TEST(mu_test_furi_event_loop) { test_furi_event_loop(); } +MU_TEST(mu_test_furi_event_loop_self_unsubscribe) { + test_furi_event_loop_self_unsubscribe(); +} + MU_TEST(mu_test_errno_saving) { test_errno_saving(); } @@ -68,6 +73,7 @@ MU_TEST_SUITE(test_suite) { MU_RUN_TEST(mu_test_furi_pubsub); MU_RUN_TEST(mu_test_furi_memmgr); MU_RUN_TEST(mu_test_furi_event_loop); + MU_RUN_TEST(mu_test_furi_event_loop_self_unsubscribe); MU_RUN_TEST(mu_test_stdio); MU_RUN_TEST(mu_test_errno_saving); MU_RUN_TEST(mu_test_furi_primitives); diff --git a/furi/core/event_loop.c b/furi/core/event_loop.c index c0998ea90..e09be0ca4 100644 --- a/furi/core/event_loop.c +++ b/furi/core/event_loop.c @@ -32,14 +32,6 @@ static void furi_event_loop_item_notify(FuriEventLoopItem* instance); static bool furi_event_loop_item_is_waiting(FuriEventLoopItem* instance); -static void furi_event_loop_process_pending_callbacks(FuriEventLoop* instance) { - for(; !PendingQueue_empty_p(instance->pending_queue); - PendingQueue_pop_back(NULL, instance->pending_queue)) { - const FuriEventLoopPendingQueueItem* item = PendingQueue_back(instance->pending_queue); - item->callback(item->context); - } -} - static bool furi_event_loop_signal_callback(uint32_t signal, void* arg, void* context) { furi_assert(context); FuriEventLoop* instance = context; @@ -130,12 +122,16 @@ static inline FuriEventLoopProcessStatus furi_event_loop_unsubscribe(instance, item->object); } + instance->current_item = item; + if(item->event & FuriEventLoopEventFlagEdge) { status = furi_event_loop_process_edge_event(item); } else { status = furi_event_loop_process_level_event(item); } + instance->current_item = NULL; + if(item->owner == NULL) { status = FuriEventLoopProcessStatusFreeLater; } @@ -193,6 +189,14 @@ static void furi_event_loop_process_waiting_list(FuriEventLoop* instance) { furi_event_loop_sync_flags(instance); } +static void furi_event_loop_process_pending_callbacks(FuriEventLoop* instance) { + for(; !PendingQueue_empty_p(instance->pending_queue); + PendingQueue_pop_back(NULL, instance->pending_queue)) { + const FuriEventLoopPendingQueueItem* item = PendingQueue_back(instance->pending_queue); + item->callback(item->context); + } +} + static void furi_event_loop_restore_flags(FuriEventLoop* instance, uint32_t flags) { if(flags) { xTaskNotifyIndexed( @@ -203,7 +207,6 @@ static void furi_event_loop_restore_flags(FuriEventLoop* instance, uint32_t flag void furi_event_loop_run(FuriEventLoop* instance) { furi_check(instance); furi_check(instance->thread_id == furi_thread_get_current_id()); - FuriThread* thread = furi_thread_get_current(); // Set the default signal callback if none was previously set @@ -213,9 +216,9 @@ void furi_event_loop_run(FuriEventLoop* instance) { furi_event_loop_init_tick(instance); - while(true) { - instance->state = FuriEventLoopStateIdle; + instance->state = FuriEventLoopStateRunning; + while(true) { const TickType_t ticks_to_sleep = MIN(furi_event_loop_get_timer_wait_time(instance), furi_event_loop_get_tick_wait_time(instance)); @@ -224,8 +227,6 @@ void furi_event_loop_run(FuriEventLoop* instance) { BaseType_t ret = xTaskNotifyWaitIndexed( FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, 0, FuriEventLoopFlagAll, &flags, ticks_to_sleep); - instance->state = FuriEventLoopStateProcessing; - if(ret == pdTRUE) { if(flags & FuriEventLoopFlagStop) { instance->state = FuriEventLoopStateStopped; @@ -448,7 +449,7 @@ void furi_event_loop_unsubscribe(FuriEventLoop* instance, FuriEventLoopObject* o WaitingList_unlink(item); } - if(instance->state == FuriEventLoopStateProcessing) { + if(instance->current_item == item) { furi_event_loop_item_free_later(item); } else { furi_event_loop_item_free(item); diff --git a/furi/core/event_loop_i.h b/furi/core/event_loop_i.h index 7016e1e1b..ef2774b97 100644 --- a/furi/core/event_loop_i.h +++ b/furi/core/event_loop_i.h @@ -64,8 +64,7 @@ typedef enum { typedef enum { FuriEventLoopStateStopped, - FuriEventLoopStateIdle, - FuriEventLoopStateProcessing, + FuriEventLoopStateRunning, } FuriEventLoopState; typedef struct { @@ -81,6 +80,7 @@ struct FuriEventLoop { // Poller state volatile FuriEventLoopState state; + volatile FuriEventLoopItem* current_item; // Event handling FuriEventLoopTree_t tree; From 3a42bf812d391999d045d998eef036f1093690f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 18 Feb 2025 03:16:14 +0900 Subject: [PATCH 14/14] Furi, USB, BLE, Debug: various bug fixes and improvements (#4114) * Furi, USB, BLE: extra stack space for some threads, small code cleanup. * Furi: thread watermark check on exit, explicitly crash if built with LIB_DEBUG=1 * Debug: color logging in apps/furi gdb helper, check and show crash message in gdb console. --- applications/main/gpio/usb_uart_bridge.c | 7 ++- furi/core/thread.c | 14 +++++ scripts/debug/flipperapps.py | 72 +++++++++++++++++++----- targets/f7/ble_glue/ble_event_thread.c | 2 +- targets/f7/furi_hal/furi_hal_usb_cdc.c | 15 +++-- 5 files changed, 87 insertions(+), 23 deletions(-) diff --git a/applications/main/gpio/usb_uart_bridge.c b/applications/main/gpio/usb_uart_bridge.c index f6e68b109..e6b71cb34 100644 --- a/applications/main/gpio/usb_uart_bridge.c +++ b/applications/main/gpio/usb_uart_bridge.c @@ -183,7 +183,7 @@ static int32_t usb_uart_worker(void* context) { usb_uart->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal); usb_uart->tx_thread = - furi_thread_alloc_ex("UsbUartTxWorker", 512, usb_uart_tx_thread, usb_uart); + furi_thread_alloc_ex("UsbUartTxWorker", 768, usb_uart_tx_thread, usb_uart); usb_uart_vcp_init(usb_uart, usb_uart->cfg.vcp_ch); usb_uart_serial_init(usb_uart, usb_uart->cfg.uart_ch); @@ -288,8 +288,6 @@ static int32_t usb_uart_worker(void* context) { usb_uart_update_ctrl_lines(usb_uart); } } - usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch); - usb_uart_serial_deinit(usb_uart); furi_hal_gpio_init(USB_USART_DE_RE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow); @@ -302,6 +300,9 @@ static int32_t usb_uart_worker(void* context) { furi_thread_join(usb_uart->tx_thread); furi_thread_free(usb_uart->tx_thread); + usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch); + usb_uart_serial_deinit(usb_uart); + furi_stream_buffer_free(usb_uart->rx_stream); furi_mutex_free(usb_uart->usb_mutex); furi_semaphore_free(usb_uart->tx_sem); diff --git a/furi/core/thread.c b/furi/core/thread.c index 6e5157957..f6cfa1d36 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -23,6 +23,8 @@ #define THREAD_MAX_STACK_SIZE (UINT16_MAX * sizeof(StackType_t)) +#define THREAD_STACK_WATERMARK_MIN (256u) + typedef struct { FuriThreadStdoutWriteCallback write_callback; FuriString* buffer; @@ -115,6 +117,18 @@ static void furi_thread_body(void* context) { furi_check(!thread->is_service, "Service threads MUST NOT return"); + size_t stack_watermark = furi_thread_get_stack_space(thread); + if(stack_watermark < THREAD_STACK_WATERMARK_MIN) { +#ifdef FURI_DEBUG + furi_crash("Stack watermark is dangerously low"); +#endif + FURI_LOG_E( //-V779 + thread->name ? thread->name : "Thread", + "Stack watermark is too low %zu < " STRINGIFY( + THREAD_STACK_WATERMARK_MIN) ". Increase stack size.", + stack_watermark); + } + if(thread->heap_trace_enabled == true) { furi_delay_ms(33); thread->heap_size = memmgr_heap_get_thread_memory((FuriThreadId)thread); diff --git a/scripts/debug/flipperapps.py b/scripts/debug/flipperapps.py index 81aa43c34..6d2d4c0a9 100644 --- a/scripts/debug/flipperapps.py +++ b/scripts/debug/flipperapps.py @@ -7,6 +7,33 @@ import zlib import gdb +class bcolors: + HEADER = "\033[95m" + OKBLUE = "\033[94m" + OKCYAN = "\033[96m" + OKGREEN = "\033[92m" + WARNING = "\033[93m" + FAIL = "\033[91m" + ENDC = "\033[0m" + BOLD = "\033[1m" + UNDERLINE = "\033[4m" + + +LOG_PREFIX = "[FURI]" + + +def error(line): + print(f"{bcolors.FAIL}{LOG_PREFIX} {line}{bcolors.ENDC}") + + +def warning(line): + print(f"{bcolors.WARNING}{LOG_PREFIX} {line}{bcolors.ENDC}") + + +def info(line): + print(f"{bcolors.OKGREEN}{LOG_PREFIX} {line}{bcolors.ENDC}") + + def get_file_crc32(filename): with open(filename, "rb") as f: return zlib.crc32(f.read()) @@ -39,12 +66,12 @@ class AppState: def is_debug_available(self) -> bool: have_debug_info = bool(self.debug_link_elf and self.debug_link_crc) if not have_debug_info: - print("No debug info available for this app") + warning("No debug info available for this app") return False debug_elf_path = self.get_original_elf_path() debug_elf_crc32 = get_file_crc32(debug_elf_path) if self.debug_link_crc != debug_elf_crc32: - print( + warning( f"Debug info ({debug_elf_path}) CRC mismatch: {self.debug_link_crc:08x} != {debug_elf_crc32:08x}, rebuild app" ) return False @@ -52,7 +79,7 @@ class AppState: def get_gdb_load_command(self) -> str: load_path = self.get_original_elf_path() - print(f"Loading debug information from {load_path}") + info(f"Loading debug information from {load_path}") load_command = ( f"add-symbol-file -readnow {load_path} 0x{self.text_address:08x} " ) @@ -121,12 +148,12 @@ class SetFapDebugElfRoot(gdb.Command): AppState.DEBUG_ELF_ROOT = arg try: global helper - print(f"Set '{arg}' as debug info lookup path for Flipper external apps") + info(f"Set '{arg}' as debug info lookup path for Flipper external apps") helper.attach_to_fw() gdb.events.stop.connect(helper.handle_stop) gdb.events.gdb_exiting.connect(helper.handle_exit) except gdb.error as e: - print(f"Support for Flipper external apps debug is not available: {e}") + error(f"Support for Flipper external apps debug is not available: {e}") class FlipperAppStateHelper: @@ -148,13 +175,29 @@ class FlipperAppStateHelper: gdb.execute(command) return True except gdb.error as e: - print(f"Failed to execute GDB command '{command}': {e}") + error(f"Failed to execute GDB command '{command}': {e}") return False + def _get_crash_message(self): + message = self.app_check_message.value() + if message == 1: + return "furi_assert failed" + elif message == 2: + return "furi_check failed" + else: + return message + def _sync_apps(self) -> None: + crash_message = self._get_crash_message() + if crash_message: + crash_message = f"! System crashed: {crash_message} !" + error("!" * len(crash_message)) + error(crash_message) + error("!" * len(crash_message)) + self.set_debug_mode(True) if not (app_list := self.app_list_ptr.value()): - print("Reset app loader state") + info("Reset app loader state") for app in self._current_apps: self._exec_gdb_command(app.get_gdb_unload_command()) self._current_apps = [] @@ -167,22 +210,23 @@ class FlipperAppStateHelper: for app in self._current_apps.copy(): if app.entry_address not in loaded_apps: - print(f"Application {app.name} is no longer loaded") + warning(f"Application {app.name} is no longer loaded") if not self._exec_gdb_command(app.get_gdb_unload_command()): - print(f"Failed to unload debug info for {app.name}") + error(f"Failed to unload debug info for {app.name}") self._current_apps.remove(app) for entry_point, app in loaded_apps.items(): if entry_point not in set(app.entry_address for app in self._current_apps): new_app_state = AppState.from_gdb(app) - print(f"New application loaded. Adding debug info") + warning(f"New application loaded. Adding debug info") if self._exec_gdb_command(new_app_state.get_gdb_load_command()): self._current_apps.append(new_app_state) else: - print(f"Failed to load debug info for {new_app_state}") + error(f"Failed to load debug info for {new_app_state}") def attach_to_fw(self) -> None: - print("Attaching to Flipper firmware") + info("Attaching to Flipper firmware") + self.app_check_message = gdb.lookup_global_symbol("__furi_check_message") self.app_list_ptr = gdb.lookup_global_symbol( "flipper_application_loaded_app_list" ) @@ -200,10 +244,10 @@ class FlipperAppStateHelper: try: gdb.execute(f"set variable furi_hal_debug_gdb_session_active = {int(mode)}") except gdb.error as e: - print(f"Failed to set debug mode: {e}") + error(f"Failed to set debug mode: {e}") # Init additional 'fap-set-debug-elf-root' command and set up hooks SetFapDebugElfRoot() helper = FlipperAppStateHelper() -print("Support for Flipper external apps debug is loaded") +info("Support for Flipper external apps debug is loaded") diff --git a/targets/f7/ble_glue/ble_event_thread.c b/targets/f7/ble_glue/ble_event_thread.c index c6bc56846..3d1fdd196 100644 --- a/targets/f7/ble_glue/ble_event_thread.c +++ b/targets/f7/ble_glue/ble_event_thread.c @@ -90,7 +90,7 @@ void ble_event_thread_stop(void) { void ble_event_thread_start(void) { furi_check(event_thread == NULL); - event_thread = furi_thread_alloc_ex("BleEventWorker", 1024, ble_event_thread, NULL); + event_thread = furi_thread_alloc_ex("BleEventWorker", 1280, ble_event_thread, NULL); furi_thread_set_priority(event_thread, FuriThreadPriorityHigh); furi_thread_start(event_thread); } diff --git a/targets/f7/furi_hal/furi_hal_usb_cdc.c b/targets/f7/furi_hal/furi_hal_usb_cdc.c index cfedb5e76..f9c1d3a42 100644 --- a/targets/f7/furi_hal/furi_hal_usb_cdc.c +++ b/targets/f7/furi_hal/furi_hal_usb_cdc.c @@ -392,10 +392,11 @@ static void cdc_on_suspend(usbd_device* dev); static usbd_respond cdc_ep_config(usbd_device* dev, uint8_t cfg); static usbd_respond cdc_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback); + static usbd_device* usb_dev; -static FuriHalUsbInterface* cdc_if_cur = NULL; -static bool connected = false; -static CdcCallbacks* callbacks[IF_NUM_MAX] = {NULL}; +static volatile FuriHalUsbInterface* cdc_if_cur = NULL; +static volatile bool connected = false; +static volatile CdcCallbacks* callbacks[IF_NUM_MAX] = {NULL}; static void* cb_ctx[IF_NUM_MAX]; FuriHalUsbInterface usb_cdc_single = { @@ -506,8 +507,10 @@ uint8_t furi_hal_cdc_get_ctrl_line_state(uint8_t if_num) { void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len) { if(if_num == 0) { usbd_ep_write(usb_dev, CDC0_TXD_EP, buf, len); - } else { + } else if(if_num == 1) { usbd_ep_write(usb_dev, CDC1_TXD_EP, buf, len); + } else { + furi_crash(); } } @@ -515,8 +518,10 @@ int32_t furi_hal_cdc_receive(uint8_t if_num, uint8_t* buf, uint16_t max_len) { int32_t len = 0; if(if_num == 0) { len = usbd_ep_read(usb_dev, CDC0_RXD_EP, buf, max_len); - } else { + } else if(if_num == 1) { len = usbd_ep_read(usb_dev, CDC1_RXD_EP, buf, max_len); + } else { + furi_crash(); } return (len < 0) ? 0 : len; }