From 67beebfc6d93732270923909cf6f9aefc49c3e8b Mon Sep 17 00:00:00 2001 From: Bjoern Hempel Date: Sun, 25 Jan 2026 20:39:52 +0100 Subject: [PATCH 1/3] Add new images and localization files for German and English - Added various PNG images for UI elements in the RF2 scripts. - Created German localization file (de.lua) with translations for menu titles and messages. - Created English localization file (en.lua) with translations for menu titles and messages. --- src/SCRIPTS/RF2/F/language.lua | 33 +++++++++ src/SCRIPTS/RF2/IMG/acc.png | Bin 0 -> 529 bytes src/SCRIPTS/RF2/IMG/advanced.png | Bin 0 -> 626 bytes src/SCRIPTS/RF2/IMG/esc.png | Bin 0 -> 420 bytes src/SCRIPTS/RF2/IMG/fblstatus.png | Bin 0 -> 770 bytes src/SCRIPTS/RF2/IMG/filters.png | Bin 0 -> 473 bytes src/SCRIPTS/RF2/IMG/flrtr.png | Bin 0 -> 490 bytes src/SCRIPTS/RF2/IMG/governor.png | Bin 0 -> 551 bytes src/SCRIPTS/RF2/IMG/hobbywing.png | Bin 0 -> 777 bytes src/SCRIPTS/RF2/IMG/info.png | Bin 0 -> 457 bytes src/SCRIPTS/RF2/IMG/mainrotor.png | Bin 0 -> 530 bytes src/SCRIPTS/RF2/IMG/mixer.png | Bin 0 -> 592 bytes src/SCRIPTS/RF2/IMG/msp_exp.png | Bin 0 -> 750 bytes src/SCRIPTS/RF2/IMG/pids-bandwidth.png | Bin 0 -> 681 bytes src/SCRIPTS/RF2/IMG/pids-controller.png | Bin 0 -> 750 bytes src/SCRIPTS/RF2/IMG/pids.png | Bin 0 -> 757 bytes src/SCRIPTS/RF2/IMG/rates.png | Bin 0 -> 719 bytes src/SCRIPTS/RF2/IMG/rescue.png | Bin 0 -> 484 bytes src/SCRIPTS/RF2/IMG/rfstatus.png | Bin 0 -> 633 bytes src/SCRIPTS/RF2/IMG/scorpion.png | Bin 0 -> 689 bytes src/SCRIPTS/RF2/IMG/servos.png | Bin 0 -> 488 bytes src/SCRIPTS/RF2/IMG/settings.png | Bin 0 -> 584 bytes src/SCRIPTS/RF2/IMG/xdfly.png | Bin 0 -> 540 bytes src/SCRIPTS/RF2/IMG/yge.png | Bin 0 -> 399 bytes src/SCRIPTS/RF2/LANG/de.lua | 32 +++++++++ src/SCRIPTS/RF2/LANG/en.lua | 32 +++++++++ src/SCRIPTS/RF2/LVGL/mainMenu.lua | 92 +++++++++++++++++++----- src/SCRIPTS/RF2/pages.lua | 67 +++++++++++------ src/SCRIPTS/RF2/tool.lua | 4 ++ src/SCRIPTS/RF2/ui_init.lua | 6 ++ src/SCRIPTS/RF2/ui_lvgl_framework.lua | 17 +++-- 31 files changed, 239 insertions(+), 44 deletions(-) create mode 100644 src/SCRIPTS/RF2/F/language.lua create mode 100644 src/SCRIPTS/RF2/IMG/acc.png create mode 100644 src/SCRIPTS/RF2/IMG/advanced.png create mode 100644 src/SCRIPTS/RF2/IMG/esc.png create mode 100644 src/SCRIPTS/RF2/IMG/fblstatus.png create mode 100644 src/SCRIPTS/RF2/IMG/filters.png create mode 100644 src/SCRIPTS/RF2/IMG/flrtr.png create mode 100644 src/SCRIPTS/RF2/IMG/governor.png create mode 100644 src/SCRIPTS/RF2/IMG/hobbywing.png create mode 100644 src/SCRIPTS/RF2/IMG/info.png create mode 100644 src/SCRIPTS/RF2/IMG/mainrotor.png create mode 100644 src/SCRIPTS/RF2/IMG/mixer.png create mode 100644 src/SCRIPTS/RF2/IMG/msp_exp.png create mode 100644 src/SCRIPTS/RF2/IMG/pids-bandwidth.png create mode 100644 src/SCRIPTS/RF2/IMG/pids-controller.png create mode 100644 src/SCRIPTS/RF2/IMG/pids.png create mode 100644 src/SCRIPTS/RF2/IMG/rates.png create mode 100644 src/SCRIPTS/RF2/IMG/rescue.png create mode 100644 src/SCRIPTS/RF2/IMG/rfstatus.png create mode 100644 src/SCRIPTS/RF2/IMG/scorpion.png create mode 100644 src/SCRIPTS/RF2/IMG/servos.png create mode 100644 src/SCRIPTS/RF2/IMG/settings.png create mode 100644 src/SCRIPTS/RF2/IMG/xdfly.png create mode 100644 src/SCRIPTS/RF2/IMG/yge.png create mode 100644 src/SCRIPTS/RF2/LANG/de.lua create mode 100644 src/SCRIPTS/RF2/LANG/en.lua diff --git a/src/SCRIPTS/RF2/F/language.lua b/src/SCRIPTS/RF2/F/language.lua new file mode 100644 index 00000000..4c510d76 --- /dev/null +++ b/src/SCRIPTS/RF2/F/language.lua @@ -0,0 +1,33 @@ +local function loadTranslations(l) + local file = "LANG/" .. l .. ".lua" + local chunk, err = rf2.loadScript(file) + if not chunk then + -- It's normal for a language file not to exist, so we don't log an error. + -- The fallback mechanism will handle it. + return nil + end + local ok, result = pcall(chunk) + if not ok then + return nil + end + return result +end + +--- +-- Loads the translation file for the current system language. +-- It falls back to English ('en') if the system language file is not found, +-- and then to an empty table if English is also not found. +-- @return table The translations table. +local function getTranslations() + local settings = getGeneralSettings() + local lang = settings.language + local translations = loadTranslations(lang) or loadTranslations("en") or {} + + function translations.t(key, default) + return translations[key] or default + end + + return translations +end + +return getTranslations() \ No newline at end of file diff --git a/src/SCRIPTS/RF2/IMG/acc.png b/src/SCRIPTS/RF2/IMG/acc.png new file mode 100644 index 0000000000000000000000000000000000000000..01302fdcc972b05d875ebd013dc400ce43b605b0 GIT binary patch literal 529 zcmV+s0`C2ZP)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUzk4Z#9R5(wCQaw+?P!uhVEIKd{KNfW{X&f9)SWO(z#og!+aWzij zA`1(QtyTpFZ9Uv>x35gobo{^bgQKeI(|R_AmP)0~`FyTnvacx08-$OxZM&Z5`L$Z@ z=HDjWZugQ5o=hfR$z(D@1cSlg8IS>24|IbK8i>c^KEYhq{Vo=ZekPMS%jI$fI4DG; z(GQv*s4?Y&I2aCxQm@xLK%-R@K0-~=0-gpSSVBC{bDE}^mSv^!oKJ$G6HVs=4Jwt2 z0=rx+7CRIK;TS=t@d-=iXf#p-9cUn*&qpA7A-+lSt0(BXE=!WMMe~_8>|Yy(@j9E$ z-uwN2s$4GbFv+Y7i0@$k9$&l5;)LQzT_+1A%koJmk-mg=5pOq;fk(1{3u`)^8l6rj zus5`JS=a0JQ>=4ywE$>fw_2^+wPY3u!TxwWZXyR8lh0YaP+Szn?M9<<6h`_5K>H&k TczTDT00000NkvXXu0mjfc-GSZ literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/IMG/advanced.png b/src/SCRIPTS/RF2/IMG/advanced.png new file mode 100644 index 0000000000000000000000000000000000000000..2636bbbf4382283f198abb1c8bd485e34c9b69db GIT binary patch literal 626 zcmV-&0*(ENP)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUz@JU2LR5(waQ%g$%Q52rZ@$EuGFhZeCk_JIYs|W-kZRf^y{eviI z)4FgGwMcO1Dnbzb0cK=ckqdLtqSAaIitk6@a{{w-uZ@glfgQNqGv|EYch5QZ4jBvv z7gZ|N$rKndfqj5wGMQaUtyY^A3dQ;a+#ysb6q>1cJRYglYWDvK053u!VjvKBoB^9e zB%jY0^m_dg=EPz#x(^1st6VO>777I$0BR_Ptk>)HlgXs5(P(TX5{dIKERDD$gOkhU ztI*dRhr_W*rBY$H+kM9%m@i3^W{1NOh4>E4Z&>VzfJ`Qv6^q3b2q`+9&b`%Y-N@x~ zci^MyP7MabvCrpQ8L}CNX@M!ZTCHBW-R}KjvDo)|y?ailb2FRG-l9C@Fbr{qLTmw; zf#2it>^GZD3~aaC{ZgqEgWjK0snkt6oqk~pQ0#IlmC7|dET7S6JcL$o3T8qG1cG^J zz@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUzB1uF+R5(v#U>Nd%5$1#U@85T^v9ZYz82zdsQX5h(+!{rU4J z*REZ=Z2$cE^Y1^A0HhYA2WSu%BalC-={ zdGh2*1(4AM;(#;){m6&U1t2vbFB~~?q#J12KE~g_f7h_Euz&**2)+R=*#@Msx&SB+ za)B3+=7I$x11KuUjYd!sfZO!u&6_SxPEMi{5>Vq4At511LV`Md2vYz(_tZLstazRP O0000#J=5 literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/IMG/fblstatus.png b/src/SCRIPTS/RF2/IMG/fblstatus.png new file mode 100644 index 0000000000000000000000000000000000000000..5f6a076d5000ae4b1444ac177e89e8312ad0efff GIT binary patch literal 770 zcmV+d1O5DoP)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU!fJsC_R5(v#WIzIig@v5IfB&}P;o(6RhO>YC`0-UnM&?XONy#4! z1;>vc&wKv-`NwbHzWoO(#EQRu{rd0e)2ENuuV0@dEiEksGK3LCoIH6l&(P3t!mC%W zF1~s5X8HH;-x>b@|Bqn_J3BkKgoH$*kdTnfx^?RcqNAfHF;rDmalUx*;^X7TkI!dk zXLDibLKB!aZ5rR}*RLPny?gg@cz8Gq6Ufi}{QP|H-o0Bsb?Ve_AoXEkVLYv^tyb6! zYiw-%4fN^(K|w(&R#sLqCJqh`1|}vZ2B5#;>I(`A@`3o^+_`fd(G7X|^5u7Naq-JQ zJxoA@G?|bTz&yQ7Zk~&70Eo}X$OsQ07MOy+fB$9x126-~XX54MRe1L7 z83Qn+{aRXD6irM_?2L_#>wp@;feW%wo6!Kux>#^z^!567ur$Oy1t!{yI83X`Gy# z?59qhO18GPo(GZ#Mt2#IasjcC!vLliOapEEcjd~JMcmxn>~G(`z1!T}yah!8l*0l_ zoz@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUzS4l)cR5(v#U>LL@At8Z%^XAP}y1Kd?WI1y6>eY5XfByWxeED)C zdm z9Xqz>>({SufVLZa`0#-NXpkZy0~mREd1bk|xf$lon`aAjy3f<6PhSEx{=0VV+9@Dk z6KDXJq@<+C|NsBtX1#v>n&I!?zmFLXA3hxY>C>nGApHIN_y6b5pTGa($B+M?KY#we zVZ(;}j~_q&xqSKZS(q9a4HW->uDx{W(m$Zlj6m=QXz~f5tq+0W@L|)Y zO}m_&oS4edjxX=(DwgVu3R~b&3lY5Uc9&o^u{faZ0tj6eyDD8{9Dh>HUNxoM@FdUz@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUzXh}ptR5(wilD$d;Q4odK7}>(Y%J^4kqe#F;@fidgD+AHS(igC` zwGk|Att4F}5X=i`W0Ot`i3BW+S_Krvtf28bml-h@i9Z8}Gc$MQ+?m}QMgO!u?@y9s z6o2g(deu0NPt)E&aF56w@x~8CPN+Fh-RA@f5Qrg7@zh1+m9t|o0`eUKU79+MxM+q% z85F__B*vjV&`Yqws)y8VgIQ4XZ!k@elUNTsvU5!!J9mKvOH^Rp@YUJ`yI>MrGVK67 z1)jmJ3+PZ*V#K2PfoRZL`=AAGKn4th2DOha;3L(nsS4{|$okD!LleOj%c~}G0sa4X zP^Vx5_LZzQ(1itK##iDr4Z2CmJ9|uvR-nhSZocTne4i{#s|mDI3S3)(uTw{`VL5$^ z6wo?5U><~tB%uHK0JfCCeEd8OOO_Lz@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUzrAb6VR5(v#U>In?h|2-Jy}d#f78cIDyu1#tU%&n@BO|l?;lqcD zTefW3Icd_Q*SPdCw6(P>*|TRSef;?GF^K!=)2HwI_wRRy8Nh^W z(xy$DywcLrE-ET2`t$SivjNpJ05!b*_wV0#pi5*x{5Nmj?0fR$$+4!UCa_)>m;oIf z9hL?L1|dL=ocHeCy9=~&=e&9IKHj=@>$$P9F$*&@^An%}zmFX|Hd8@C!8ANPd@j(7 zreOV5RaF8{pFVxOYSpSTpdbB^U4_gJ3JPL8apFYY=g*&i0=<<1m%DJ`Lj9{(uip0e z_iN(P43rZ9x@PU4KY#w;zkh!jP#rT^EzlXPckkZ4zjEbD8(f;#u3c;K^5x5Wpg?^0 z?%lQO>S|%Q+Mb>sb)d;paA`hx@L>M8Z{NOxG=Kg2^~ct&TMbauPM<#AW5tRU4mb?p z{qp6@2ax8!fB*gm`a2U{9Scyw6=1+TMVEl`Kfizf{w6CctJ$MRkCp<{$P66na0{E8 po3n?6gy?c|a^g(2xOEQ+834fP;sNULWQza*002ovPDHLkV1j+u09pV5 literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/IMG/hobbywing.png b/src/SCRIPTS/RF2/IMG/hobbywing.png new file mode 100644 index 0000000000000000000000000000000000000000..a37f63b5fcc7936e55b205091a720455240f028b GIT binary patch literal 777 zcmV+k1NQuhP)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU!hem>((Knx>OP#6rGo7huv!73lm|OA!2wCH643H$21dNS`Ia*IPLqFxi+TsgXjPI z@w`8u|3jf1Jye^`c4lpD?M1a(eZ9K6I(gKkk7jOe?nE}5{ZOmb+O1ZrBl&#Z*vGx2 zrgn`!pKnyHR(n}2)>x@ja*`5{$LmxoH7XDYt_p?1K{lKHUZGI@=#`K_rLUDr<##ff z)bw&N7!1PY<>hCQNaXRv#KeB#j&CRwy0Npfv)eEDV8T=?HHFTm4;3jC3X1?%tk>(- zJ()qmnP4zDxxT(01Js+{0KHyMOQ+L|=tQ!g1ntK%nam>ujUxNSa=BcARKejJ?w=Nm zg?F%GG#Z@-?3bjDMt(@zfk2=*Ffj0)!C>45tRbj>ak<>{TU%S+k&%(J9*^go)oLB{ z`~8<;s{-ylhr@A-K_(yw!mm^+DMq7FD3i$^Vx%CAMiViaOp07CzXSUvu~;mVNF-sA zNVKuNz5NHtxf~8hPA3!Sbh-wQ$Ge56x6x>1W3kvQx=G=EjL+wf4i66t=yW;*oFb@v zx7}`!p}=XCO7)bCCl4JP_t|c@U+60E79gMmUYW<5zN0FRAPbdW26c@2=SLuy*B)`D(jiA3VvUhKci<#O?{EN_;UmY&Sd z&#PhSE)3P}c8{a#r)IO++T7fH-ifnE6+4u^ZLdEZ26doY*F@tjU4r=QbbQg~BuCR_~x00000NkvXX Hu0mjfV}x8G literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/IMG/info.png b/src/SCRIPTS/RF2/IMG/info.png new file mode 100644 index 0000000000000000000000000000000000000000..825dc9d501a5836d91a46ef7877829544235ac2d GIT binary patch literal 457 zcmV;)0XF`LP)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUzM@d9MR5(wiQ$1^hKoHfKGFaHEox$?{fPW)b*!o)z^hYSEER6L* zDiKp?AzUkdfMR1~aiqJG%f1Up+}o3bOtG+UX5S3+-g4YOgJ--Kecyl6b$u&I(hJY? z+%!#PRaJpySzmqM9~p0cA;)oywrvmR^Z7!@>2$g@O>?kq+h7tPF$}|zen{U@gGLJy zMNves)5UQdCs7n7G>$0=fe4Z(9Iopcs;X}2(b6>CXIZwVaaoo(*wc*Hb^T6v!JRCw zD$BBBFbsFB925fnjDvJw)d1)3ap7ohWB{7o@T}B00000NkvXXu0mjf06V<8 literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/IMG/mainrotor.png b/src/SCRIPTS/RF2/IMG/mainrotor.png new file mode 100644 index 0000000000000000000000000000000000000000..f36c370d2c10259f16c83e2bad303284b08a556d GIT binary patch literal 530 zcmV+t0`2{YP)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUzkV!;AR5(wiQ^9V6KoDJUAske|#H*nP6OZ%*Na>*;;1Bc*dgzCE zEFaRuTMyDp6L0oL;$_>59yCw|43tP`Hi3Y_nzWN_GCS|>o86gNLjGw&)A`9{f^k}4 zd7cx-SmroRe##f-^ZAu&n)j_%tHk#Ey_#j&LsbCqCskFyirDdZB(Cc|(|*5i!N$gb zD2j$G%SOB1b}6M&H5&+CgNU7`DFZG;Y&aZ#(Di!#DF}j#0bSQ^6sR6N^$&*w^L?N5 zH=7NkilS(P!N3L)&V~0P81PNq0>rxAE`enu6o%pZDT(icATU;|)gxRr$Av!B#b_dn zO+ii5nCE$m0z<#k>98hlO#re;Ns{md1&tv48!q&Vcoapo;+Au;-EJkw;zRZ2rc6Z) zx{<=$^Nl2Uy`Vpv z&F-MRujoS?$#^{G*?%=Sgu}(Vfc`mh`Gh6{{((z&R$#eYE=Hr#EefE2N$Ah`4_qz@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUz&PhZ;R5(v#V88>as;VR=PoAuaM+ttZ`}gl({`m3ZkD#C+30x{! za7lo~FJHcVgq@w8d)>NqAMvTfDfj&O^Nk-qe0U91z=}%|6E2AvGiI+jaBzt9 z_4S$KQioN1&6+iy&z?QI^&bk}zkmPX#EBDGSQVoSu3x|2>&urf|9<@V@f&E!W*}Y+ z^v37EfB*hFe*AbVx_S)$qeqW!egFRb_mU+`qG6IvO-RI0JIQ_3PKy1q1{zqZrcC(!#N2%a#t1 z^I;+X=FOXD=g*(7K6mb1*5k*IPk{^u0T6xc*sz@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU!Y)M2xR5(wyQoC!~Q523NoaXgo4E>w;uVw0+?Plsh#-i?LZN^XiNujm zDEzvzva$tWFE|{|w|G3hZ8DjDQ-5h7PknlN3PgE$GewihgoJYpa#HFMv=cxO<#M^= z@pu@wN_;+_-G8$uIF;O?=!V@IvvD?Ua!}V#bO6WqmeuR z8Q(F$Xfz_{0qD^4Cy-rrxm+hwsdN!cG_~99OSM{kFB**wDKLx0qJp;WGZ+lo@$vEd z84~E}?O-q%wpuOJXf&{zVJ4IDQ;)1x>mvaDft7YTogs|)300$OG#ci{#)gu|<2|?A z?Fxs(v9DArv3U>KY_?A%5=}NYH}~Kp2S)o7JgRcJ+{X}~!7F0H?RGEr`+bznX3r?p z^Ye2fNs=fW4j;lMp1@S_Sa05>QmM1QW`+y~1C8EnHb=|L%S~X~UR_-cf)8kYef=He zbHH}FwzjrYDwS&0YBdG>p%4fJ;%>Lw;Pd%U#bPo0hBOoky}r7-8iA4_jFSK#egT^s zCiDTbVKsO^r~vR5Oa#HAeYxF4nM@{dI-P3p;+aaNIs{b&^tq(fYTtnTr5V@Z!eX%+ gu%#d8^LM`g0Uf!7cX@o+hyVZp07*qoM6N<$f?_yLS^xk5 literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/IMG/pids-bandwidth.png b/src/SCRIPTS/RF2/IMG/pids-bandwidth.png new file mode 100644 index 0000000000000000000000000000000000000000..7313a4a2ce00db2174ce3b480c1b181e53ce1e2b GIT binary patch literal 681 zcmV;a0#^NrP)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU!CrLy>R5(v#V88(#IFU8uV=rF3nDgMl zgU^6!M8IB9QBmO*5fQY(D{0q6sj3CIG{r?)L55sXzn3`oIPNlPe=Ix|o0gqXJYcAq)hJ zjEwADTwJ`sl*j<|GbaZJhbE9MCn_o`^!V{(CSV!?MeA>H;Mm&QNNI`td?>`WadVIrh? P00000NkvXXu0mjfJlHCq literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/IMG/pids-controller.png b/src/SCRIPTS/RF2/IMG/pids-controller.png new file mode 100644 index 0000000000000000000000000000000000000000..0f5e871b53a55bbd0f58d2f8b3168b8201c22eb3 GIT binary patch literal 750 zcmVz@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU!Y)M2xR5(w4Q_pJ}Q4oG_HG+s56t$ILC;@G=H$9{vIi_em6%s7; zqVW>w!IK~&*nqZze?TerV0#O>RcHgT#ZXTr(t}B~{zNafx(XV9V2p0(ZEI-B>Vx6E z{rG0)o0%Pq=A2+KcxQ8SbBATw!O6+VVIUCb&Y|9h?RLAm(P*4cr&E?#E|)v=`Fw)g z%sEK0SbPkb*+e4oI-AWNP9_u9%gf93csyo1olc97%Zu&p z?NOOb<{fbyjYe0=Wb&=iXvDna1)$*a^0EqQiVHZ1w}ihA6N;k7q?AR6leMI zOb!kRrqCf6F^xuZS1cAk$>;O0U|Lfl37}9Y(9+VlcteC5dXsPT8_FR{7sue3kpKVy07*qoM6N<$f*fH^vH$=8 literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/IMG/pids.png b/src/SCRIPTS/RF2/IMG/pids.png new file mode 100644 index 0000000000000000000000000000000000000000..3df79d211812dc67fc88efa9e9f8691032a47627 GIT binary patch literal 757 zcmVz@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU!b4f%&R5(v{Q%#6caS(q`H&a|#$zM0iT$s?d+A_O7amclUtD;}I7Z7oYTceQOPs5$0#J*;a^Sni#9fE6&(6+1U=?_JGMW6L zP$&fJ$c#9g%xX59(L$lHP%4!-8A$*#wt(cz%S(#O<#zCWGMTK4C&-n@>-D~nN~H&E zHv5_^kw_jx3%4qj%2$#kDRiJVtyb%JZ*TA8H8B>8k)2LwI2a75Mx(J-YQAa5$W4G#V);*ua}yF2@I*N~ON1(`f~Wx2#O3)A?bEo;n;3!OqUk6fu=bW!&1@ zdc)`Q@51NrWrCIA-e|SjB@qp_Z&|k6?Vf^|OCdm;`9JT~-DotDnM}qAvGaPp-U2P2 zpzGx1%IB!7Up-3d!22Fn2Y&I1LNsGl|DdF?^bf`3phJtz1`Fy@=x7)YjbQsD2 zE2E+8xy$9c4>}}qJ7K{ntlIDQA7N|kNF;Iuqw?o+IhWOHl_3bu{c^eNt5&N%D0Lq( nv)L?zztjb~_=CaVJBz@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU!O-V#SR5(wqQ_G7|aTKE zm$N7^3{4Rqh`MpGXqt!uEQ-%JF!N;W$oU7)G>Ot*qT{e@O+= zYPBcDV)0upm-__yTbnnN$#fVBg`Qa~7P{Z>7uM_ba{$4o(tD!Jbg5MOST2|ID9wc1?UrseqmOhtO#-X~rhaF!SbI91ZbKVQb~>H! zpnQ)CaCH}LGMW4Ujc<57-myR+2r-$=1IQ5|={mrES{ z(&ciwzxxDfZnxXysZgX+sV^K3=NgrAKA%5F17fk*>n$nBBvjhN;gCRb%H?uErBWTO zi>+4cbI9YhS}nZ+&}cM|sCP!R9S+Aau<0Tuyk$$fBQa5kHfO957B(V_W#jsw6~X#I6kv)TLvZvPqn2jP~k%MVyCr&_I^ zfinSXMgYhX-23WJwSUd2)oOaFR60~Dm3P*KKLLU~#+Kx+?#2KB002ovPDHLkV1j(6 BJre)` literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/IMG/rescue.png b/src/SCRIPTS/RF2/IMG/rescue.png new file mode 100644 index 0000000000000000000000000000000000000000..8d806a413563df0964b64b51a2f3d1a8c279f7a7 GIT binary patch literal 484 zcmVz@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUzVo5|nR5(v#U>FEcRaM1TUtiCLV)yCOrzOswJX`nYHFC!4Y_*ts`U5o-*^A|_3J+f{QLLs|L4!2 zH9+dXif`Sz^^}Q;X`7IcP-1#|dL_C6K!d*lE#PNmWd%zC4fwia$BtJh>gLUxC-?2! zw|js7{P}m|#*F}E$)27bCZN+7fUO6DFJHc(YKAEWhJy*vso#J9{{0%r)`y9I{P-~e z6Wx_?{>zsyy?_RQ{CNM_vuAv_Z{KzU`u#5u-&?zOtvpVRFp0>> zNX7>b9<+dL1p58r&!0bE{{Vtx$BsD=)QqeE=+u=U|Ni~^_y6C;P2ARt8}Fl-j`@bKiafHVO^zDP<+3U4w-HyoH2E})AI a3?Bf{3);)_zkJjH0000z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUz_en%SR5(wSlRs!8K@`SUHe#V&)JBWwVU=rQr4YgrY;(lIN~;he zS_&3dsMm=nmMIh@RzW<$TqztLTxDUJD{St>MiKRpweSzSareGwm_?(6WMJ5to%g-> zoA=)6xIH5pjhY<}$48sZ#x zhkqN5M$+&1^NB=47Yqh=@mRE2EGH(DDT40>&Tb+8 z3a8wBKEJNjYU)~FsZ`Dvi^UTnJ?8WI58GTE7Yc>=TrQ{YbUHB7MnM|Z=wR)AwWOlG)vDgu4Q>v;SX|$UJrBdl|G#WipLUHGxl(5Y^ z!+}7h#SkH@raHRx^DH3eXdcB@B z7z|`mqhK=aG0)Z{n|%QBP9IRs1A%}ZBt9ZrE|)&qW9qb)e9?*Ds1s+inP@Z`Pw+iO zQg5tQ>oHpS2V(l{cKa_a4{Y(;Tfo^TMnaL9Mq6xpi$o%3r_=fV*SLf9h9Ca{pqrH^ TBm)fO00000NkvXXu0mjfCIb{j literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/IMG/scorpion.png b/src/SCRIPTS/RF2/IMG/scorpion.png new file mode 100644 index 0000000000000000000000000000000000000000..d486e0eab85b53f1caaf95abf398e136386823f0 GIT binary patch literal 689 zcmV;i0#5yjP)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU!FG)l}R5(x7QcH`HQ5g37)X)1hMO}D-G&h06K;jIu3TZaw%&rJ` zL5o&JEviM!AjUPFB@&6QO{dc<*mLOnUavP{u~?D8VDP0>D*d$CY|BmF8Xy=9 z5@xg6sZc1ME*6W)d_Mm?8jWInKEJVAtr+9+SSb()w(;}^lgZ>Xo6YCRWb%W<;aCxw zOoq^CG_K`xxmT%F9w33KQmGDFt=2oE(U{ETa)ewizr*A4wrjQ8s?+I&^?Ln1k|e*C z%jHKTo6UC8$!@oM-|zSTl1inwLI00LB6$@Gg)V{q4nYvF)9JLa(P$)Qz*H-)^_9FmiV?ne1Y`0K)}hB$vzm8V-kV(uLrK0q5TYoZr&vbSKbv zC=?2x0PsS+UZ>#2N105fg`qZ7*X8s1XD*lPZ6FYs77B&SxI0C$t83QKci8Xuvj91Y zMx*+T6ngb|JQM&ZdLM~I4CufS-j))H#G1+3KLCgV-MEi_-@KG7!UoUeZY X9*qotR2sQ500000NkvXXu0mjf5-mFh literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/IMG/servos.png b/src/SCRIPTS/RF2/IMG/servos.png new file mode 100644 index 0000000000000000000000000000000000000000..511d7af88b093d0a5667f7a4d4e1fa77c4c1ae8d GIT binary patch literal 488 zcmVP)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUzW=TXrR5(v#V4x5%hIgPZ&^l01`95OP$Za{nR$75ctl^l zdUXLC7zR>6zi+`}DNN|Uw6t{I@87?dv$C?j0qQ-<2$Na6c5Q~ez5UdW zA3y%VV*mp`KR+8#t!8?9`VEjelvofJ7G?rsHhc#B`t=J%8YLaz(}+tB*??ETu*9Vf zE)ELsCr_UI#ZU;0Le^{7uI&Lj@fRo=W5eIRefxF#^yy{Dn&E+nBq$GL3uD*-5qJxv e9^#NAPZ$8c9`2w>v13mF0000z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUz#z{m$R5(w4Q@e`7KolKg@P$}wC&HFie!>2Ly|xxwEZA+gg_T%a zC~RrFgrO%-qMhk8_3)!KqfOzQtmZQWT}o z@AnJK-AzTu)$#9U#(W^<#PGnZnq!j^I7B7`9Je%^ZC5K-|zMHdaZW5UH=n=8H?To z+$p8@Pjq&>UC{<8m&;+(G+h<%_dDHeHqF^=mSzh~v#y%3Ie`qr&@!1!Sk`sjcQ_or zg2CXMBuNo~GTUb&ktjLlEHOY5kH_t*49rAMHk~uObm&?73Mx$4@2a-%Cm3F&LMF2k| W7zbW&`L){s0000z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUznn^@KR5(w)QoTz8VH`FU62e7V0v+0;;S{04uu+0Yuq_;0y1&2{ z8yas=a=3$Nb1P_01VxU+FFZmJ&jW`OKafiAIKeyL>-P#lnnz^Nv%I{&_xF78+*vGt z#KyXOf*|Z}w;S2k5vWuuyP;6%PLiajU-3zjwAN}hQc;vQID-phzu)hS#bP^VikVDi zyVvVIAcPEXzW=u8^Z8t@R;!%L<%s3SQmJ%09*_G5;2n@or(MfC^ZRf(q$ZPz0uIOc z&M?eYyWM7Hv)NSFb)(bi2t3c9uO#Ck#5{tCNYgY_C=_nNmB+5Cs`dpzIElyOhtX)% zYATRQrEIT&d_Ip!m}`KZ&a&(UCebv#X-dWqq9|VC1ki&Z@Q7jgjY&LtaQXPgAMR~ye8GaxQ(k&QRyk4&}5{Wp>$e;5-AmD({d!0xm e_I}#^-}es$xc_RmHI()M0000z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUz4M{{nR5(v#U_b)*@84%e=9A3+`SWM)moHx&NYTiIteB0BjhmB` zbIY@5&%8-71g`e~|Nj+0{Qu9NKi`iZKb}RhAut0#h5)_u@95E^g(Mk*YyilRU%!6+ z1G=P$XhZ(}`&aS(`}eOue*F0I_wV2TApG&;$9o449t0b5|5Ketuh^&5uBA zMn)zEE-vz`StazyYuqfL=*HfBrm*7f?*2I1rHy tpePzCN=QI|e<3?5larZH0+F2T3;=_-<_S+uKimKS002ovPDHLkV1g}PqzeE5 literal 0 HcmV?d00001 diff --git a/src/SCRIPTS/RF2/LANG/de.lua b/src/SCRIPTS/RF2/LANG/de.lua new file mode 100644 index 00000000..1cc1f0aa --- /dev/null +++ b/src/SCRIPTS/RF2/LANG/de.lua @@ -0,0 +1,32 @@ +-- Language file for German (de) +return { + TITLE_Menu_Menu = "Hauptmenü", + TITLE_WARNING_Save = "Speichern Warnung", + MSG_WARNING_Save_later = "Einstellungen werden nach dem Entsichern gespeichert.", + TITLE_Save_Error = "Speichern Fehler", + MSG_Save_Error = "Stellen Sie sicher, dass Ihr Heli entsichert ist.", + MENU_Save = "Speichern", + MENU_Reload = "Neu laden", + MENU_Reboot = "Neustart", + PAGE_Status = "Status", + PAGE_Rates = "Drehraten", + PAGE_Rate_Dynamics = "Drehraten Adv.", + PAGE_PID_Gains = "PIDs", + PAGE_PID_Controller = "PID Regler", + PAGE_Profile_Various = "Hauptrotor", + PAGE_Profile_Rescue = "Profil - Rettung", + PAGE_Profile_Governor = "Drehzahlregler", + PAGE_Servos = "Servos", + PAGE_Mixer = "Mischer", + PAGE_Gyro_Filters = "Gyro Filter", + PAGE_Governor = "Drehzahlregler", + PAGE_Accelerometer_Trim = "ACC Trimm", + PAGE_Model = "Modell", + PAGE_Experimental = "Experimentell (!)", + PAGE_ESC_FLYROTOR = "ESC - FLYROTOR", + PAGE_ESC_HW_Platinum_V5 = "ESC - HW Platinum V5", + PAGE_ESC_Scorpion_Tribunus = "ESC - Scorpion Tribunus", + PAGE_ESC_XDFly = "ESC - XDFly", + PAGE_ESC_YGE = "ESC - YGE", + PAGE_Settings = "Einstellungen" +} \ No newline at end of file diff --git a/src/SCRIPTS/RF2/LANG/en.lua b/src/SCRIPTS/RF2/LANG/en.lua new file mode 100644 index 00000000..e1d1a16e --- /dev/null +++ b/src/SCRIPTS/RF2/LANG/en.lua @@ -0,0 +1,32 @@ +-- Language file for english (en) +return { + TITLE_Menu_Menu = "Main Menu", + TITLE_WARNING_Save = "Save warning", + MSG_WARNING_Save_later = "Settings will be saved\nafter disarming.", + TITLE_Save_Error = "Save error", + MSG_Save_Error = "Make sure your heli\nis disarmed.", + MENU_Save = "Save", + MENU_Reload = "Reload", + MENU_Reboot = "Reboot", + PAGE_Status = "Status", + PAGE_Rates = "Rates", + PAGE_Rate_Dynamics = "Rate Adv.", + PAGE_PID_Gains = "PIDs", + PAGE_PID_Controller = "PID Controller", + PAGE_Profile_Various = "Main Rotor", + PAGE_Profile_Rescue = "Profile - Rescue", + PAGE_Profile_Governor = "Governor", + PAGE_Servos = "Servos", + PAGE_Mixer = "Mixer", + PAGE_Gyro_Filters = "Gyro Filters", + PAGE_Governor = "Governor", + PAGE_Accelerometer_Trim = "ACC Trim", + PAGE_Model = "Model", + PAGE_Experimental = "Experimental (!)", + PAGE_ESC_FLYROTOR = "ESC - FLYROTOR", + PAGE_ESC_HW_Platinum_V5 = "ESC - HW Platinum V5", + PAGE_ESC_Scorpion_Tribunus = "ESC - Scorpion Tribunus", + PAGE_ESC_XDFly = "ESC - XDFly", + PAGE_ESC_YGE = "ESC - YGE", + PAGE_Settings = "Settings" +} \ No newline at end of file diff --git a/src/SCRIPTS/RF2/LVGL/mainMenu.lua b/src/SCRIPTS/RF2/LVGL/mainMenu.lua index da87540e..e03a2735 100644 --- a/src/SCRIPTS/RF2/LVGL/mainMenu.lua +++ b/src/SCRIPTS/RF2/LVGL/mainMenu.lua @@ -5,39 +5,97 @@ local function show(menu) local w = (LCD_W - 30) / 3 local h = 50 + -- --- FINE TUNING --- + local OFFSET_X = -6 -- Horizontal fits perfectly + local OFFSET_Y = 8 -- Correction to move text down + for i = 1, #menu.items do local item = menu.items[i] + + -- 1. Container Box + local content_box = { + type = "box", + w = w, + h = h, + + x = OFFSET_X, + y = OFFSET_Y, + + -- Center content + flexFlow = lvgl.FLOW_ROW, + flexAlignMain = lvgl.FLEX_ALIGN_CENTER, + flexAlignCross = lvgl.FLEX_ALIGN_CENTER, + flexGap = 5, + + children = {} + } + + -- 2. Fill content into the box + if item.icon and item.icon ~= "" then + if string.find(item.icon, ".png") then + -- >>> IMAGE ICON (.png) <<< + content_box.children[#content_box.children + 1] = { + type = "image", + file = item.icon, + w = 16, + h = 16 + } + -- Text next to it + content_box.children[#content_box.children + 1] = { + type = "label", + text = item.text, + color = lcd.RGB(255, 255, 255) + } + else + -- >>> SYMBOL ICON (FontAwesome) <<< + content_box.children[#content_box.children + 1] = { + type = "label", + text = item.icon .. " " .. item.text, + color = lcd.RGB(255, 255, 255) -- White + } + end + else + -- >>> NO ICON (Text Only) <<< + content_box.children[#content_box.children + 1] = { + type = "label", + text = item.text, + color = lcd.RGB(255, 255, 255) -- White + } + end + + -- 3. CREATE BUTTON children[#children + 1] = { type = "button", x = 6 + #children % 3 * (w + 4), y = 6 + math.floor(#children / 3) * (h + 4), w = w, h = h, - text = item.text, + color = lcd.RGB(48, 48, 48), -- Dark Gray press = function() if item.click then item.click(i) end - end + end, + children = {content_box} } end - local lyt = { - { - type = "page", - title = menu.title, - subtitle = menu.subtitle, - icon = rf2.baseDir .. "rf2.png", - back = function() - if menu.back then - menu.back() - end - end, - children = children - }, - } + local lyt = {{ + type = "page", + title = menu.title, + subtitle = menu.subtitle, + icon = rf2.baseDir .. "rf2.png", + back = function() + if menu.back then + menu.back() + end + end, + children = children + }} lvgl.build(lyt) end -return { show = show } \ No newline at end of file +return { + show = show +} diff --git a/src/SCRIPTS/RF2/pages.lua b/src/SCRIPTS/RF2/pages.lua index ad911683..b86e3c50 100644 --- a/src/SCRIPTS/RF2/pages.lua +++ b/src/SCRIPTS/RF2/pages.lua @@ -1,45 +1,70 @@ local PageFiles = {} local settings = rf2.loadSettings() +local t = rf2.i18n.t + +local SYMBOL = { + RATES = rf2.baseDir .. "IMG/" .. "rates.png", + PID = rf2.baseDir .. "IMG/" .. "pids.png", + STATUS = rf2.baseDir .. "IMG/" .. "rfstatus.png", + PID_CONTROLLER = rf2.baseDir .. "IMG/" .. "pids-controller.png", + PROFILE = rf2.baseDir .. "IMG/" .. "profile.png", + MAINROTOR = rf2.baseDir .. "IMG/" .. "mainrotor.png", + RESCUE = rf2.baseDir .. "IMG/" .. "rescue.png", + GOVERNOR = rf2.baseDir .. "IMG/" .. "governor.png", + SERVOS = rf2.baseDir .. "IMG/" .. "servos.png", + MIXER = rf2.baseDir .. "IMG/" .. "mixer.png", + FILTERS = rf2.baseDir .. "IMG/" .. "filters.png", + ACCELEROMETER = rf2.baseDir .. "IMG/" .. "acc.png", + FBLSTATUS = rf2.baseDir .. "IMG/" .. "fblstatus.png", + MSP_EXP = rf2.baseDir .. "IMG/" .. "msp_exp.png", + FLRTR = rf2.baseDir .. "IMG/" .. "fltr.png", + HOBBYWING = rf2.baseDir .. "IMG/" .. "hobbywing.png", + SCORPION = rf2.baseDir .. "IMG/" .. "scorpion.png", + XDFLY = rf2.baseDir .. "IMG/" .. "xdfly.png", + YGE = rf2.baseDir .. "IMG/" .. "yge.png", + SETTINGS = rf2.baseDir .. "IMG/" .. "settings.png", + ADVANCED = rf2.baseDir .. "IMG/" .. "advanced.png" +} -- Rotorflight pages. -PageFiles[#PageFiles + 1] = { title = "Status", script = "status" } -PageFiles[#PageFiles + 1] = { title = "Rates", script = "rates" } -PageFiles[#PageFiles + 1] = { title = "Rate Dynamics", script = "rate_dynamics" } -PageFiles[#PageFiles + 1] = { title = "PID Gains", script = "profile_pids" } -PageFiles[#PageFiles + 1] = { title = "PID Controller", script = "profile_pidcon" } -PageFiles[#PageFiles + 1] = { title = "Profile - Various", script = "profile_various" } -PageFiles[#PageFiles + 1] = { title = "Profile - Rescue", script = "profile_rescue" } -PageFiles[#PageFiles + 1] = { title = "Profile - Governor", script = "profile_governor" } -PageFiles[#PageFiles + 1] = { title = "Servos", script = "servos" } -PageFiles[#PageFiles + 1] = { title = "Mixer", script = "mixer" } -PageFiles[#PageFiles + 1] = { title = "Gyro Filters", script = "filters" } -PageFiles[#PageFiles + 1] = { title = "Governor", script = "governor" } -PageFiles[#PageFiles + 1] = { title = "Accelerometer Trim", script = "accelerometer" } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Status", "Status"), script = "status", icon=SYMBOL.STATUS } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Rates", "Rates"), script = "rates", icon=SYMBOL.RATES } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Rate_Dynamics", "Rate Dynamics"), script = "rate_dynamics", icon=SYMBOL.ADVANCED } +PageFiles[#PageFiles + 1] = { title = t("PAGE_PID_Gains", "PID Gains"), script = "profile_pids", icon=SYMBOL.PID } +PageFiles[#PageFiles + 1] = { title = t("PAGE_PID_Controller", "PID Controller"), script = "profile_pidcon", icon=SYMBOL.PID_CONTROLLER } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Various", "Profile - Various"), script = "profile_various", icon=SYMBOL.MAINROTOR } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Rescue", "Profile - Rescue"), script = "profile_rescue", icon=SYMBOL.RESCUE } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Governor", "Profile - Governor"), script = "profile_governor", icon=SYMBOL.GOVERNOR } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Servos", "Servos"), script = "servos", icon=SYMBOL.SERVOS } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Mixer", "Mixer"), script = "mixer", icon=SYMBOL.MIXER } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Gyro_Filters", "Gyro Filters"), script = "filters", icon=SYMBOL.FILTERS } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Governor", "Governor"), script = "governor", icon=SYMBOL.GOVERNOR } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Accelerometer_Trim", "Accelerometer Trim"), script = "accelerometer", icon=SYMBOL.ACCELEROMETER } if rf2.apiVersion >= 12.07 then if settings.showModelOnTx == 1 then - PageFiles[#PageFiles + 1] = { title = "Model", script = "model" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_Model", "Model"), script = "model", icon=SYMBOL.FBLSTATUS } end if settings.showExperimental == 1 then - PageFiles[#PageFiles + 1] = { title = "Experimental (!)", script = "experimental" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_Experimental", "Experimental (!)"), script = "experimental", icon=SYMBOL.MSP_EXP } end if settings.showFlyRotor == 1 then - PageFiles[#PageFiles + 1] = { title = "ESC - FLYROTOR", script = "esc_flyrotor" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_FLYROTOR", "ESC - FLYROTOR"), script = "esc_flyrotor", icon=SYMBOL.FLRTR } end if settings.showPlatinumV5 == 1 then - PageFiles[#PageFiles + 1] = { title = "ESC - HW Platinum V5", script = "esc_hwpl5" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_HW_Platinum_V5", "ESC - HW Platinum V5"), script = "esc_hwpl5", icon=SYMBOL.HOBBYWING } end if settings.showTribunus == 1 then - PageFiles[#PageFiles + 1] = { title = "ESC - Scorpion Tribunus", script = "esc_scorp" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_Scorpion_Tribunus", "ESC - Scorpion Tribunus"), script = "esc_scorp", icon=SYMBOL.SCORPION } end if rf2.apiVersion >= 12.08 and settings.showXdfly == 1 then - PageFiles[#PageFiles + 1] = { title = "ESC - XDFly", script = "esc_xdfly" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_XDFly", "ESC - XDFly"), script = "esc_xdfly", icon=SYMBOL.XDFLY } end if settings.showYge == 1 then - PageFiles[#PageFiles + 1] = { title = "ESC - YGE", script = "esc_yge" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_YGE", "ESC - YGE"), script = "esc_yge", icon=SYMBOL.YGE } end - PageFiles[#PageFiles + 1] = { title = "Settings", script = "settings" } + PageFiles[#PageFiles + 1] = { title = t("PAGE_Settings", "Settings"), script = "settings", icon=SYMBOL.SETTINGS } end return PageFiles diff --git a/src/SCRIPTS/RF2/tool.lua b/src/SCRIPTS/RF2/tool.lua index 4c56c636..43c8d85a 100644 --- a/src/SCRIPTS/RF2/tool.lua +++ b/src/SCRIPTS/RF2/tool.lua @@ -7,6 +7,10 @@ local useLvgl = false if scriptsCompiled then --print("RF2: Before rf2.lua: ", collectgarbage("count") * 1024) assert(loadScript("rf2.lua"))() + + local i18n = assert(loadScript("F/language.lua"))() + rf2.i18n = i18n + --rf2.showMemoryUsage("rf2 loaded") rf2.radio = rf2.executeScript("radios").msp --rf2.showMemoryUsage("radios loaded") diff --git a/src/SCRIPTS/RF2/ui_init.lua b/src/SCRIPTS/RF2/ui_init.lua index 2e2576a2..b19a7149 100644 --- a/src/SCRIPTS/RF2/ui_init.lua +++ b/src/SCRIPTS/RF2/ui_init.lua @@ -9,6 +9,12 @@ local function init() return false end + if rf2.runningInSimulator then + rf2.apiVersion = apiVersion or 12.06 + collectgarbage() + return true + end + if not apiVersion and (not lastRunTS or lastRunTS + 2 < rf2.clock()) then returnTable.t = "Waiting for API version" mspApiVersion.getApiVersion(function(_, version) apiVersion = version end) diff --git a/src/SCRIPTS/RF2/ui_lvgl_framework.lua b/src/SCRIPTS/RF2/ui_lvgl_framework.lua index f8668712..81c27193 100644 --- a/src/SCRIPTS/RF2/ui_lvgl_framework.lua +++ b/src/SCRIPTS/RF2/ui_lvgl_framework.lua @@ -12,6 +12,8 @@ local ui = { previousState = nil } +local t = rf2.i18n.t + local PageFiles = nil local Page = nil local CurrentPageIndex = -1 @@ -42,12 +44,14 @@ ui.loadPage = function() Page:read() end + + ui.showMainMenu = function() Page = nil local menu = { title = "Rotorflight " .. rf2.luaVersion, - subtitle = "Main Menu", + subtitle = t("TITLE_Menu_Menu", "Main Menu"), items = {}, back = function() ui.state = ui.status.exit end } @@ -63,6 +67,7 @@ ui.showMainMenu = function() local text = string.gsub(page.title, "^ESC %- ", "") -- remove leading 'ESC - ' from page title menu.items[#menu.items + 1] = { text = text, + icon = page.icon, click = onMenuItemClick } end @@ -104,9 +109,9 @@ ui.saveSettingsToEeprom = function(eepromWrite, reboot) if not ui.saveWarningShown then ui.saveWarningShown = true if rf2.apiVersion >= 12.08 then - rf2.executeScript("LVGL/messageBox").show("Save warning", "Settings will be saved\nafter disarming.") + rf2.executeScript("LVGL/messageBox").show(t("TITLE_WARNING_Save", "Save warning"), t("MSG_WARNING_Save_later", "Settings will be saved\nafter disarming.")) else - rf2.executeScript("LVGL/messageBox").show("Save error", "Make sure your heli\nis disarmed.") + rf2.executeScript("LVGL/messageBox").show(t("TITLE_Save_Error", "Save error"), t("MSG_Save_Error", "Make sure your heli\nis disarmed.")) end ui.refresh() end @@ -122,19 +127,19 @@ ui.showPopupMenu = function() if Page then if not Page.readOnly then menu.items[#menu.items + 1] = { - text = "Save", + text = t("MENU_Save", "Save"), click = function() Page:write() end } end menu.items [#menu.items + 1] = { - text = "Reload", + text = t("MENU_Reload", "Reload"), click = function() Page:read() end } end menu.items[#menu.items + 1] = { - text = "Reboot", + text = t("MENU_Reboot", "Reboot"), click = function() rebootFc() end } From 81db29a1b11d6ef4d55a233beab3b8721e72f075 Mon Sep 17 00:00:00 2001 From: Bjoern Hempel Date: Tue, 27 Jan 2026 15:53:29 +0100 Subject: [PATCH 2/3] Add question box dialog and enhance various pages with translations - Introduced a new `questionBox.lua` script for displaying dialog boxes with customizable buttons. - Added a new `page.luac` file for LVGL page handling. - Enhanced the `accelerometer.lua` page to utilize the new question box for calibration confirmation. - Updated the `model.lua` page to include translations for various fields and labels. - Improved the `rate_dynamics.lua` and `rates.lua` pages by adding help messages and translating labels. - Enhanced the `status.lua` page with help messages and improved the display of arming disabled flags. - Updated the `pages.lua` file to use translated titles for various pages. - Improved the `ui_lvgl_framework.lua` to utilize translations for menu items and messages. --- src/SCRIPTS/RF2/F/language.lua | 4 +- src/SCRIPTS/RF2/LANG/de.lua | 80 ++++++++++- src/SCRIPTS/RF2/LANG/en.lua | 80 ++++++++++- src/SCRIPTS/RF2/LVGL/page.lua | 183 ++++++++++++++++++------ src/SCRIPTS/RF2/LVGL/page.luac | Bin 0 -> 4254 bytes src/SCRIPTS/RF2/LVGL/questionBox.lua | 31 ++++ src/SCRIPTS/RF2/PAGES/accelerometer.lua | 70 ++++++++- src/SCRIPTS/RF2/PAGES/model.lua | 35 ++--- src/SCRIPTS/RF2/PAGES/rate_dynamics.lua | 8 ++ src/SCRIPTS/RF2/PAGES/rates.lua | 25 ++-- src/SCRIPTS/RF2/PAGES/status.lua | 84 ++++++----- src/SCRIPTS/RF2/pages.lua | 42 +++--- src/SCRIPTS/RF2/ui_lvgl_framework.lua | 12 +- 13 files changed, 505 insertions(+), 149 deletions(-) create mode 100644 src/SCRIPTS/RF2/LVGL/page.luac create mode 100644 src/SCRIPTS/RF2/LVGL/questionBox.lua diff --git a/src/SCRIPTS/RF2/F/language.lua b/src/SCRIPTS/RF2/F/language.lua index 4c510d76..4dd33023 100644 --- a/src/SCRIPTS/RF2/F/language.lua +++ b/src/SCRIPTS/RF2/F/language.lua @@ -23,8 +23,8 @@ local function getTranslations() local lang = settings.language local translations = loadTranslations(lang) or loadTranslations("en") or {} - function translations.t(key, default) - return translations[key] or default + function translations.t(key) + return translations[key] or key end return translations diff --git a/src/SCRIPTS/RF2/LANG/de.lua b/src/SCRIPTS/RF2/LANG/de.lua index 1cc1f0aa..6dfb44c5 100644 --- a/src/SCRIPTS/RF2/LANG/de.lua +++ b/src/SCRIPTS/RF2/LANG/de.lua @@ -5,15 +5,15 @@ return { MSG_WARNING_Save_later = "Einstellungen werden nach dem Entsichern gespeichert.", TITLE_Save_Error = "Speichern Fehler", MSG_Save_Error = "Stellen Sie sicher, dass Ihr Heli entsichert ist.", - MENU_Save = "Speichern", - MENU_Reload = "Neu laden", - MENU_Reboot = "Neustart", + MENU_Save = "\xEF\x80\x99 Speichern", + MENU_Reload = "\xEF\x80\xA1 Neu laden", + MENU_Reboot = "\xEF\x81\xB9 Neustart", PAGE_Status = "Status", PAGE_Rates = "Drehraten", PAGE_Rate_Dynamics = "Drehraten Adv.", PAGE_PID_Gains = "PIDs", PAGE_PID_Controller = "PID Regler", - PAGE_Profile_Various = "Hauptrotor", + PAGE_Profile_Various = "Profil - versch.", PAGE_Profile_Rescue = "Profil - Rettung", PAGE_Profile_Governor = "Drehzahlregler", PAGE_Servos = "Servos", @@ -28,5 +28,75 @@ return { PAGE_ESC_Scorpion_Tribunus = "ESC - Scorpion Tribunus", PAGE_ESC_XDFly = "ESC - XDFly", PAGE_ESC_YGE = "ESC - YGE", - PAGE_Settings = "Einstellungen" + PAGE_Settings = "Einstellungen", + PAGE_Status_PID_Profile = "Aktuelles PID Profil", + PAGE_Status_Rate_Profile = "Aktuelles Raten Profil", + PAGE_Status_Real_Time_Load = "Echtzeit Last", + PAGE_Status_CPU_Load = "CPU Last", + PAGE_Status_Arming_Flags = "Arming Sperrgründe", + PAGE_Status_Dataflash_Free = "Dataflash freier Speicher", + PAGE_Status_Erase = "[Löschen]", + MSG_Erasing = "Lösche...", + ARMING_DISABLED_NO_GYRO = "Kein Gyro", + ARMING_DISABLED_FAIL_SAFE = "Failsafe", + ARMING_DISABLED_RX_FAIL_SAFE = "RX Failsafe", + ARMING_DISABLED_BAD_RX_RECOVERY = "Schlechte RX Erholung", + ARMING_DISABLED_BOX_FAIL_SAFE = "Box Failsafe", + ARMING_DISABLED_GOVERNOR = "Drehzahlregler", + ARMING_DISABLED_RPM_SIGNAL = "RPM Signal", + ARMING_DISABLED_THROTTLE = "Gas", + ARMING_DISABLED_ANGLE = "Winkel", + ARMING_DISABLED_BOOT_GRACE_TIME = "Boot Wartezeit", + ARMING_DISABLED_NO_PRE_ARM = "Kein Pre-Arm", + ARMING_DISABLED_LOAD = "Systemlast", + ARMING_DISABLED_CALIBRATING = "Kalibrierung", + ARMING_DISABLED_CLI = "CLI", + ARMING_DISABLED_CMS_MENU = "CMS Menü", + ARMING_DISABLED_BST = "BST", + ARMING_DISABLED_MSP = "MSP", + ARMING_DISABLED_PARALYZE = "Paralyze", + ARMING_DISABLED_GPS = "GPS", + ARMING_DISABLED_RESC = "Rettung", + ARMING_DISABLED_RPM_FILTER = "RPM Filter", + ARMING_DISABLED_REBOOT_REQUIRED = "Neustart erforderlich", + ARMING_DISABLED_DSHOT_BITBANG = "DSHOT Bitbang", + ARMING_DISABLED_ACC_CALIBRATION = "ACC Kalibrierung", + ARMING_DISABLED_MOTOR_PROTOCOL = "Motor Protokoll", + ARMING_DISABLED_ARM_SWITCH = "Arm Schalter", + ACC_Title = "Beschleunigungssensor", + ACC_Label = "Beschleunigungssensor Trimm", + ACC_Roll = "Roll", + ACC_Pitch = "Nick", + ACC_Calibrate = "Kalibrieren", + ACC_Calibrating = "Kalibriere...", + ACC_Help_title = "Beschleunigungssensor", + ACC_Help_text = "Der Beschleunigungssensor wird verwendet, um den Winkel des Flugcontrollers in Bezug auf den Horizont zu messen. Diese Daten werden zur Stabilisierung des Fluggeraets und zur Bereitstellung der Selbstnivellierungsfunktion verwendet.", + ACC_Calibration_Question = "Beschleunigungssensor kalibrieren?\nStellen Sie sicher, dass das Fluggerät auf einer ebenen Oberfläche platziert ist und während des Kalibrierungsprozesses ruhig bleibt.", + MENU_Yes = "Ja", + MENU_No = "Nein", + STATUS_Help_title = "Status", + STATUS_Help_text = "Diese Seite zeigt den aktuellen Status des Flugcontrollers an, einschließlich PID- und Ratenprofile, Systemlast und Arming-Sperrgründe.", + RATES_Help_title = "Drehraten", + RATES_Help_text = "Diese Seite ermöglicht es Ihnen, die Raten und Expos für Ihren Hubschrauber zu konfigurieren. Sie können Roll-, Nick-, Gier- und Kollektivraten sowie deren entsprechende Exponentialwerte anpassen.", + RATES_ADVANCE_Help_title = "Drehraten - Erweitert", + RATES_ADVANCE_Help_text = "Dynamik: Wird unabhaengig vom Rate-Typ angewendet. Anpassen, um Heli-Bewegungen weicher zu machen, z. B. fuer Scale-Helis.", + MENU_Dest_Profile = "Ziel Profil", + MENU_Copy_Profile = "[Kopiere Akt. nach Ziel]", + Rates_Yaw = "Gier", + Rates_Coll = "Kollektiv", + Rates_Type = "Raten Typ", + Model_ID = "Modell ID", + Model_Stats = "Statistiken", + Model_Stats_Enabled = "Aktiviert", + Model_Total_Flights = "Anzahl Flüge", + Model_Total_Time = "Gesamtzeit", + Model_Total_Dist = "Gesamtdistanz", + Model_Min_Armed_Time = "Min. Armed Zeit", + Model_Reset_Stats = "[Statistiken zurücksetzen]", + Model_Radio_Config = "Funk Konfiguration", + Model_Requires_Rf2bg = "Hinweis: benötigt rf2bg", + Model_Set_Name_Tx = "Name auf Sender setzen", + Model_Param = "Param", + Model_Type = "Typ", + Model_Value = "Wert", } \ No newline at end of file diff --git a/src/SCRIPTS/RF2/LANG/en.lua b/src/SCRIPTS/RF2/LANG/en.lua index e1d1a16e..30298bdf 100644 --- a/src/SCRIPTS/RF2/LANG/en.lua +++ b/src/SCRIPTS/RF2/LANG/en.lua @@ -5,15 +5,15 @@ return { MSG_WARNING_Save_later = "Settings will be saved\nafter disarming.", TITLE_Save_Error = "Save error", MSG_Save_Error = "Make sure your heli\nis disarmed.", - MENU_Save = "Save", - MENU_Reload = "Reload", - MENU_Reboot = "Reboot", + MENU_Save = "\xEF\x80\x99 Save", + MENU_Reload = "\xEF\x80\xA1 Reload", + MENU_Reboot = "\xEF\x81\xB9 Reboot", PAGE_Status = "Status", PAGE_Rates = "Rates", PAGE_Rate_Dynamics = "Rate Adv.", PAGE_PID_Gains = "PIDs", PAGE_PID_Controller = "PID Controller", - PAGE_Profile_Various = "Main Rotor", + PAGE_Profile_Various = "Profile-Various", PAGE_Profile_Rescue = "Profile - Rescue", PAGE_Profile_Governor = "Governor", PAGE_Servos = "Servos", @@ -28,5 +28,75 @@ return { PAGE_ESC_Scorpion_Tribunus = "ESC - Scorpion Tribunus", PAGE_ESC_XDFly = "ESC - XDFly", PAGE_ESC_YGE = "ESC - YGE", - PAGE_Settings = "Settings" + PAGE_Settings = "Settings", + PAGE_Status_PID_Profile = "Current PID profile", + PAGE_Status_Rate_Profile = "Current rate profile", + PAGE_Status_Real_Time_Load = "Real-time load", + PAGE_Status_CPU_Load = "CPU load", + PAGE_Status_Arming_Flags = "Arming Disabled Flags", + PAGE_Status_Dataflash_Free = "Dataflash Free Space", + PAGE_Status_Erase = "[Erase]", + MSG_Erasing = "Erasing...", + ARMING_DISABLED_NO_GYRO = "No Gyro", + ARMING_DISABLED_FAIL_SAFE = "Fail Safe", + ARMING_DISABLED_RX_FAIL_SAFE = "RX Fail Safe", + ARMING_DISABLED_BAD_RX_RECOVERY = "Bad RX Recovery", + ARMING_DISABLED_BOX_FAIL_SAFE = "Box Fail Safe", + ARMING_DISABLED_GOVERNOR = "Governor", + ARMING_DISABLED_RPM_SIGNAL = "RPM Signal", + ARMING_DISABLED_THROTTLE = "Throttle", + ARMING_DISABLED_ANGLE = "Angle", + ARMING_DISABLED_BOOT_GRACE_TIME = "Boot Grace Time", + ARMING_DISABLED_NO_PRE_ARM = "No Pre Arm", + ARMING_DISABLED_LOAD = "Load", + ARMING_DISABLED_CALIBRATING = "Calibrating", + ARMING_DISABLED_CLI = "CLI", + ARMING_DISABLED_CMS_MENU = "CMS Menu", + ARMING_DISABLED_BST = "BST", + ARMING_DISABLED_MSP = "MSP", + ARMING_DISABLED_PARALYZE = "Paralyze", + ARMING_DISABLED_GPS = "GPS", + ARMING_DISABLED_RESC = "Resc", + ARMING_DISABLED_RPM_FILTER = "RPM Filter", + ARMING_DISABLED_REBOOT_REQUIRED = "Reboot Required", + ARMING_DISABLED_DSHOT_BITBANG = "DSHOT Bitbang", + ARMING_DISABLED_ACC_CALIBRATION = "Acc Calibration", + ARMING_DISABLED_MOTOR_PROTOCOL = "Motor Protocol", + ARMING_DISABLED_ARM_SWITCH = "Arm Switch", + ACC_Title = "Accelerometer", + ACC_Label = "Accelerometer Trim", + ACC_Roll = "Roll", + ACC_Pitch = "Pitch", + ACC_Calibrate = "Calibrate", + ACC_Calibrating = "Calibrating...", + ACC_Help_title = "Accelerometer", + ACC_Help_text = "The accelerometer is used to measure the angle of the flight controller in relation to the horizon. This data is used to stabilize the aircraft and provide self-leveling functionality.", + ACC_Calibration_Question = "Calibrate the accelerometer?\nMake sure the aircraft is placed on a level surface and will remain stationary during the calibration process.", + MENU_Yes = "Yes", + MENU_No = "No", + STATUS_Help_title = "Status", + STATUS_Help_text = "This page shows the current status of the flight controller, including PID and rate profiles, system load and arming disabled flags.", + RATES_Help_title = "Rates", + RATES_Help_text = "This page allows you to configure the rates and expos for your helicopter. You can adjust roll, pitch, yaw, and collective rates as well as their corresponding", + RATES_ADVANCE_Help_title = "Rates - Advanced", + RATES_ADVANCE_Help_text = "Dynamics: Applied regardless of rates type. Typically left on defaults but can be adjusted to smooth heli movements, like with scale helis.", + MENU_Dest_Profile = "Destination profile", + MENU_Copy_Profile = "[Copy Current to Dest]", + Rates_Yaw = "Yaw", + Rates_Coll = "Coll", + Rates_Type = "Rates type", + Model_ID = "Model ID", + Model_Stats = "Statistics", + Model_Stats_Enabled = "Enabled", + Model_Total_Flights = "Total flights", + Model_Total_Time = "Total time", + Model_Total_Dist = "Total distance", + Model_Min_Armed_Time = "Min armed time", + Model_Reset_Stats = "[Reset Stats]", + Model_Radio_Config = "Radio Configuration", + Model_Requires_Rf2bg = "Note: requires rf2bg", + Model_Set_Name_Tx = "Set name on TX", + Model_Param = "Param", + Model_Type = "type", + Model_Value = "value", } \ No newline at end of file diff --git a/src/SCRIPTS/RF2/LVGL/page.lua b/src/SCRIPTS/RF2/LVGL/page.lua index 124a958c..0b601cf6 100644 --- a/src/SCRIPTS/RF2/LVGL/page.lua +++ b/src/SCRIPTS/RF2/LVGL/page.lua @@ -16,42 +16,55 @@ local function show(page) end local function fieldIsButton(f) - -- TODO: refactor return f.t and string.sub(f.t, 1, 1) == "[" and not f.data end local children = {} + + -- OFFSET: Schiebt den Inhalt unter die Toolbar (35px Höhe + Abstand) + local CONTENT_OFFSET = 25 + + local specialFunction = nil + + -- 1. LABELS ERSTELLEN for i = 1, #page.labels do local label = page.labels[i] children[#children + 1] = { type = "label", x = label.x, - y = label.y + 3, - --text = label.t, -- no updates - text = function() return label.t end, -- does update + y = label.y + 3 + CONTENT_OFFSET, + text = function() return label.t end, font = (not (label.bold == false)) and BOLD or 0 } end + -- 2. FELDER ERSTELLEN for i = 1, #page.fields do local field = page.fields[i] + local fieldY = field.y + CONTENT_OFFSET + if field.t then children[#children + 1] = { type = "label", x = field.x, - y = field.y, + y = fieldY, text = field.t, } end - if fieldIsButton(field) then + if field.special then + rf2.log("Found special field at index " .. i) + specialFunction = function() + if field.preEdit then field.preEdit(field, page) end + end + elseif fieldIsButton(field) then children[#children + 1] = { type = "button", x = field.x, - y = field.y, + y = fieldY, w = field.w or 200, text = function() - local s = string.gsub(field.t, "[%[%]]", "") -- remove brackets around [button] + local s = string.gsub(field.t, "[%[%]]", "") return s end, press = function() @@ -64,97 +77,187 @@ local function show(page) child = { type = "label", x = field.sp or field.x, - y = field.y + 3, + y = fieldY + 3, text = field.data.value, } else child = { type = "textEdit", x = field.sp or field.x, - y = field.y, + y = fieldY, w = field.w or 125, value = field.data.value, length = field.data.max or 10, } end - children[#children + 1] = child + elseif field.data and field.data.value and type(field.data.value) == "number" then local child if field.readOnly then child = { type = "label", x = field.sp or field.x, - y = field.y + 3, + y = fieldY + 3, text = function() return formatVal(field.data.value, field) end, } elseif field.data.table then local choiceTable = lvglHelper.toChoiceTable(field.data.table, field.data.max + 1) - --rf2.print("Choice with value: " .. tostring(field.data.value)) child = { type = "choice", - --title = "todo", values = choiceTable.values, x = field.sp or field.x, - y = field.y, + y = fieldY, w = field.w or 100, get = function() return choiceTable:getChoiceKey(field.data.value) end, set = function(val) field.data.value = choiceTable:getOriginalKey(val) - if field.postEdit then - field:postEdit(page) - end + if field.postEdit then field:postEdit(page) end end, } else child = { type = "numberEdit", x = field.sp or field.x, - y = field.y, + y = fieldY, w = field.w or 75, - get = function() - return field.data.value / (field.data.mult or 1) - end, + get = function() return field.data.value / (field.data.mult or 1) end, set = function(val) local newVal = math.ceil(val * (field.data.mult or 1)) - if field.change then - field:change(newVal, page) - end + if field.change then field:change(newVal, page) end field.data.value = newVal - --rf2.print("Value after editing: %s", tostring(field.data.value)) - end, - display = function(val) - return formatVal(val * (field.data.mult or 1), field) end, + display = function(val) return formatVal(val * (field.data.mult or 1), field) end, } if field.data.min then child.min = field.data.min / (field.data.mult or 1) end if field.data.max then child.max = field.data.max / (field.data.mult or 1) end end - children[#children + 1] = child end end + -- 3. SKALIERUNG ANWENDEN (Nur auf den alten Inhalt!) + for i = 1, #children do + local child = children[i] + child.x = child.x * 1.75 + child.y = (child.y - rf2.radio.yMinLimit + 5) * 1.75 + end + + -- 4. TOOLBAR ERSTELLEN (Manuelle Positionierung) + + local toolbar = { + type = "button", + clickable = false, -- Nur als Hintergrund + + x = 0, + y = 0, + w = LCD_W, + h = 42, + + color = lcd.RGB(48, 48, 48), -- Dunkelgrau + padAll = 0, -- Kein Padding, wir positionieren selbst + + children = {} + } + + -- 4.1 BUTTONS VON RECHTS NACH LINKS AUFBAUEN + -- Wir starten am rechten Bildschirmrand und gehen schrittweise nach links. + + local currentX = LCD_W - 5 -- Startpunkt: 5px Abstand vom rechten Rand + local btnHeight = 30 -- Höhe der Buttons + local btnY = 2 -- Y-Position in der Toolbar (zentriert bei h=35) + + -- A) HELP BUTTON (?) (Ganz rechts) + if page.help then + local btnW = 40 + currentX = currentX - btnW - 10 -- X-Position berechnen + + toolbar.children[#toolbar.children + 1] = { + type = "button", + text = "?", + x = currentX, + y = btnY, + w = btnW, + h = btnHeight, + press = function() + rf2.executeScript("LVGL/messageBox").show(page.help.title, page.help.msg) + end, + } + currentX = currentX - 5 -- Lücke zum nächsten Button + end + + -- B) TOOLS BUTTON (*) (Links daneben) + if page.specialFunction then + local btnW = 40 + + currentX = currentX - btnW + if page.help == nil then + currentX = currentX - 10 -- Abstand, wenn kein Help-Button + end + + toolbar.children[#toolbar.children + 1] = { + type = "button", + text = "*", + x = currentX, + y = btnY, + w = btnW, + h = btnHeight, + press = function() + page.specialFunction() + end, + } + currentX = currentX - 5 -- Lücke + end + + -- TOOLS Reload (*) (Links daneben) + -- if page.read then + -- local btnW = 40 + + -- currentX = currentX - btnW + -- if page.help == nil then + -- currentX = currentX - 10 -- Abstand, wenn kein Help-Button + -- end + + -- toolbar.children[#toolbar.children + 1] = { + -- type = "button", + -- text = "\xEF\x80\xA1", + -- x = currentX, + -- y = btnY, + -- w = btnW, + -- h = btnHeight, + -- press = function() + -- page.read() + -- end, + -- } + -- currentX = currentX - 5 -- Lücke + -- end + + -- C) SAVE BUTTON (Links daneben) if page.isReady and not page.readOnly then - children[#children + 1] = { + local btnW = 100 + currentX = currentX - btnW + if page.help == nil and page.tools == nil then + currentX = currentX - 10 -- Abstand, wenn kein Help und Tools-Button + end + + toolbar.children[#toolbar.children + 1] = { type = "button", - x = 5, - y = children[#children].y + 35, - w = LCD_W - 20, - text = "Save", + text = rf2.i18n.t("MENU_Save"), + x = currentX, + y = btnY, + w = btnW, + h = btnHeight, + press = function() page:write() end, } end - for i = 1, #children do - local child = children[i] - child.x = child.x * 1.75 - child.y = (child.y - rf2.radio.yMinLimit + 5) * 1.75 - end + -- 5. Toolbar ganz am Ende hinzufügen + children[#children + 1] = toolbar local lyt = { { diff --git a/src/SCRIPTS/RF2/LVGL/page.luac b/src/SCRIPTS/RF2/LVGL/page.luac new file mode 100644 index 0000000000000000000000000000000000000000..04f25f50f432d0a49d196e1e1677c21acb7cbb7f GIT binary patch literal 4254 zcmb_f-ESjT6+d_8&P+bru&yflLAq3FK~)8X7eG98?8(|~HtDuWTOO9Ga_mVm>co!h z$u|1{d+o`_Qql?#6nJQ>Dq6Kb^9KM=wnw|(W}97sfTt=#RUi8gAc4y7+_85zY*y+6 zW8FFTo^$W{KIe`fnq4n0&;!35A9-*@^0V^hSrMC$jX3P^Rb-{jOuFmXW1a&agf) zlsM?Ntx@Pd5_g(~Bx{X$aa=HS)|}V1=gfvZ;+dOaOayqbV0zZ8ZemX=Qu)}UMUQBb zNM#cf^!VaF#nxf>iwhq#{&gXhJAF%T<9m=ht>yNNoONI{EXSL+9)&%VuAv?_l^9Q4 z`?M)&2D-GM%S;@{Gl{X;!oHcj?K_uwb2-(Wosn@=bw z&ZqjTaXojEysc%ZF=cyMDu7-{uGlR55h~b|G^!-*EqDcMQQK{*oA$zH%eXGiQ9(stb96ThkF@iWd%TNAzK=gj}dh{ase zwh>SJ(0KT!ork%Hj@Wsad+-=LpS2IWUp;Ckn0^^M_jEi4HfB`8d)6w%AKBVhcKCc_T$(?E&&&BBbR#c%K+br zM+o?x&-rW;zxBCk0Ghuhlbm^VfTcUjK%D zTQFy>g7}~NFqj}^r>gu<8Pki<08LaPq#{5MZ!;jM#a!q!6sL3&| zMe< zeCB%Rz!c31?3b~3orzz# zIFmHu8PC|9iJLn!rt!|6X|mtn*w2|Z^KNzfJjqIVHkxM7n5ReFzgpb4z~8((|M@%l zd;iOSKGj({@MVE^bI`wSt44E#uHP=JO{!-sd?~qG-U7Aa1*erPI34pox`f`rb$^Gg z@hx56MjwB(J8SJLVeJ@-t~CYi=l<3d$$gXuzk>O9`)i(Q?;Gato%luCH{w6oz&puH zcGkR~`m_(9L>~ujZ@;VF`!J{Iis4eP`40>AV11TLFRin1v11gR$1%6nr zOCyp)^)rY*au8*HqO}P9%5thbiBn!taWVAeJyF$LsRkwgMZI)NdLbPxsh%nGLAmTlQr7VrO<8CurRxAfqIdXn3sLTedP|)I|Bc(7Xy{4twv)=Tp zKa$2u<_V_QrD|BMNg0;PQqC80nWq@*tQE`IFqFfkl^`tF{7MG7PZ`u2yw4vQnQ!vc zcv?>Mots~;l%fF6)MSvJkV8Rz9!@(i?WkHsi1lZS6@2IW@OUIg=1x8L(yI%_bH23J zipz+76hv^+_LLK6-wt}0bvruf(CFQw99_CAZ zWo_`_U=FH8B1EZT#@RGY@1oBX4)Q=q*c$%yeZ0?;Pk<)_!Ol4P`~b@zYLqzyzy}`% zWY6;a6y_J9;FPPhH#M^%)HRop0iqZ=Mxz`Ed=i2OO!-4R53e-Z1V0Fxf=31#TD);! zvb7AGwGYldcJ{GXUXg;u9IJaC=w~$X|ET*C7_OvD9RSuXPi_5u&yIME*bxNp!T`WQ zN76lq5kef}-0kMVcsA+|HE4C&$sX($;p`AM~fRfoc)s$B3xo+&K(n zrEx;Cbe+T7#*4o~R6 z!>hQ?akb>C8|h!-^l}>9G;+1R%u2C|cRV+M`HRNhY)}xYt>fKy+= 12.09 then incY(lineSpacing * 0.5) - labels[#labels + 1] = { t = "Statistics", x = x, y = incY(lineSpacing) } - fields[#fields + 1] = { t = "Enabled", x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.statsEnabled, + labels[#labels + 1] = { t = t("Model_Stats"), x = x, y = incY(lineSpacing) } + fields[#fields + 1] = { t = t("Model_Stats_Enabled"), x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.statsEnabled, postEdit = function(self, page) if self.data.value == 0 then flighStats.stats_min_armed_time_s.value = -1 -- stats disabled @@ -45,7 +46,7 @@ local function buildForm(page) } if flighStats.statsEnabled.value and flighStats.statsEnabled.value == 1 then - fields[#fields + 1] = { t = "Total flights", x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_total_flights, readOnly = true } + fields[#fields + 1] = { t = t("Model_Total_Flights"), x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_total_flights, readOnly = true } local function formatSeconds(seconds) local days = math.floor(seconds / 86400) @@ -64,10 +65,10 @@ local function buildForm(page) end end local totalTime = formatSeconds(flighStats.stats_total_time_s.value) - fields[#fields + 1] = { t = "Total time", x = x, y = incY(lineSpacing), sp = x + sp, data = { value = totalTime }, readOnly = true } + fields[#fields + 1] = { t = t("Model_Total_Time"), x = x, y = incY(lineSpacing), sp = x + sp, data = { value = totalTime }, readOnly = true } - fields[#fields + 1] = { t = "Total distance", x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_total_dist_m, readOnly = true } - fields[#fields + 1] = { t = "Min armed time", x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_min_armed_time_s } + fields[#fields + 1] = { t = t("Model_Total_Dist"), x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_total_dist_m, readOnly = true } + fields[#fields + 1] = { t = t("Model_Min_Armed_Time"), x = x, y = incY(lineSpacing), sp = x + sp, data = flighStats.stats_min_armed_time_s } local function resetStats(self, page) flighStats.stats_total_flights.value = 0 @@ -76,13 +77,13 @@ local function buildForm(page) buildForm(page) rf2.onPageReady(page) end - fields[#fields + 1] = { t = "[Reset Stats]", x = x + indent * 3, y = incY(lineSpacing * 1.3), preEdit = resetStats } + fields[#fields + 1] = { t = t("Model_Reset_Stats"), x = x + indent * 3, y = incY(lineSpacing * 1.3), preEdit = resetStats } end end incY(lineSpacing * 0.5) - labels[#labels + 1] = { t = "Radio Configuration", x = x, y = incY(lineSpacing) } - labels[#labels + 1] = { t = "Note: requires rf2bg", x = x + indent, y = incY(lineSpacing), bold = false } + labels[#labels + 1] = { t = t("Model_Radio_Config"), x = x, y = incY(lineSpacing) } + labels[#labels + 1] = { t = t("Model_Requires_Rf2bg"), x = x + indent, y = incY(lineSpacing), bold = false } local function getAutoSetName() if rf2.apiVersion >= 12.07 and rf2.apiVersion < 12.09 then @@ -93,15 +94,15 @@ local function buildForm(page) end incY(lineSpacing * 0.25) setNameOnTxFieldIndex = #fields + 1 - fields[setNameOnTxFieldIndex] = { t = "Set name on TX", x = x, y = incY(lineSpacing), sp = x + sp, data = { value = getAutoSetName() or 0, min = 0, max = 1, table = { [0] = "Off", "On" } } } + fields[setNameOnTxFieldIndex] = { t = t("Model_Set_Name_Tx"), x = x, y = incY(lineSpacing), sp = x + sp, data = { value = getAutoSetName() or 0, min = 0, max = 1, table = { [0] = "Off", "On" } } } incY(lineSpacing * 0.25) - fields[#fields + 1] = { t = "Param1 type", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param1_type } - fields[#fields + 1] = { t = "Param1 value", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param1_value } - fields[#fields + 1] = { t = "Param2 type", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param2_type } - fields[#fields + 1] = { t = "Param2 value", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param2_value } - fields[#fields + 1] = { t = "Param3 type", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param3_type } - fields[#fields + 1] = { t = "Param3 value", x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param3_value } + fields[#fields + 1] = { t = t("Model_Param") .. " 1 " .. t("Model_Type"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param1_type } + fields[#fields + 1] = { t = t("Model_Param") .. " 1 " .. t("Model_Value"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param1_value } + fields[#fields + 1] = { t = t("Model_Param") .. " 2 " .. t("Model_Type"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param2_type } + fields[#fields + 1] = { t = t("Model_Param") .. " 2 " .. t("Model_Value"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param2_value } + fields[#fields + 1] = { t = t("Model_Param") .. " 3 " .. t("Model_Type"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param3_type } + fields[#fields + 1] = { t = t("Model_Param") .. " 3 " .. t("Model_Value"), x = x, y = incY(lineSpacing), sp = x + sp, data = pilotConfig.model_param3_value } page.labels = labels page.fields = fields diff --git a/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua b/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua index b27a7bfa..655b3f48 100644 --- a/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua +++ b/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua @@ -14,6 +14,13 @@ local rateSwitcher = rf2.executeScript("PAGES/helpers/rateSwitcher.lua") local rcTuning = rf2.useApi("mspRcTuning").getDefaults() collectgarbage() +local t = rf2.i18n.t + +help = { + title = t("RATES_ADVANCE_Help_title"), + msg = t("RATES_ADVANCE_Help_text") +} + local tableStartY = yMinLim - lineSpacing y = tableStartY labels = {} @@ -84,6 +91,7 @@ return { labels = labels, fields = fields, rateSwitcher = rateSwitcher, + help = help, timer = function(self) self.rateSwitcher.checkStatus(self) diff --git a/src/SCRIPTS/RF2/PAGES/rates.lua b/src/SCRIPTS/RF2/PAGES/rates.lua index eadb9bfd..9e4aef17 100644 --- a/src/SCRIPTS/RF2/PAGES/rates.lua +++ b/src/SCRIPTS/RF2/PAGES/rates.lua @@ -20,6 +20,14 @@ local rcTuning = rf2.useApi("mspRcTuning").getDefaults() collectgarbage() local editing = false local profileAdjustmentTS = nil +local help = {} +local t = rf2.i18n.t + +help = { + title = t("RATES_Help_title"), + msg = t("RATES_Help_text") +} + local startEditing = function(field, page) editing = true @@ -52,10 +60,10 @@ local function buildForm() labels[#labels + 1] = { t = "", x = x, y = incY(tableSpacing.header) } labels[#labels + 1] = { t = "", x = x, y = incY(tableSpacing.header) } - labels[#labels + 1] = { t = "Roll", x = x, y = incY(tableSpacing.row) } - labels[#labels + 1] = { t = "Pitch", x = x, y = incY(tableSpacing.row) } - labels[#labels + 1] = { t = "Yaw", x = x, y = incY(tableSpacing.row) } - labels[#labels + 1] = { t = "Coll", x = x, y = incY(tableSpacing.row) } + labels[#labels + 1] = { t = t("ACC_Roll"), x = x, y = incY(tableSpacing.row) } + labels[#labels + 1] = { t = t("ACC_Pitch"), x = x, y = incY(tableSpacing.row) } + labels[#labels + 1] = { t = t("Rates_Yaw"), x = x, y = incY(tableSpacing.row) } + labels[#labels + 1] = { t = t("Rates_Coll"), x = x, y = incY(tableSpacing.row) } x = x + tableSpacing.col y = tableStartY @@ -86,12 +94,12 @@ local function buildForm() x = margin incY(lineSpacing * 0.5) - fields[13] = { t = "Rates type", x = x, y = incY(lineSpacing), sp = x + sp, data = rcTuning.rates_type, postEdit = function(self, page) page.updateRatesType(page) end } + fields[13] = { t = t("Rates_Type"), x = x, y = incY(lineSpacing), sp = x + sp, data = rcTuning.rates_type, postEdit = function(self, page) page.updateRatesType(page) end } incY(lineSpacing * 0.5) - fields[14] = { t = "Current rate profile", x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { min = 0, max = 5, value = rcTuning.currentRateProfile, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endRateEditing } - fields[15] = { t = "Destination profile", x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { min = 0, max = 5, value = rcTuning.destRateProfile, table = { [0] = "1", "2", "3", "4", "5", "6" } } } - fields[#fields + 1] = { t = "[Copy Current to Dest]", x = x + indent, y = incY(lineSpacing), preEdit = copyProfile } + fields[14] = { t = t("PAGE_Status_Rate_Profile"), x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { min = 0, max = 5, value = rcTuning.currentRateProfile, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endRateEditing } + fields[15] = { t = t("MENU_Dest_Profile"), x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { min = 0, max = 5, value = rcTuning.destRateProfile, table = { [0] = "1", "2", "3", "4", "5", "6" } } } + fields[#fields + 1] = { t = t("MENU_Copy_Profile"), x = x + indent, y = incY(lineSpacing), preEdit = copyProfile } --rf2.showMemoryUsage("after buildform") end @@ -125,6 +133,7 @@ return { title = "Rates", labels = labels, fields = fields, + help = help, updateRatesType = function(self, applyDefaults) rf2.useApi("mspRcTuning").getRateDefaults(rcTuning, rcTuning.rates_type.value) diff --git a/src/SCRIPTS/RF2/PAGES/status.lua b/src/SCRIPTS/RF2/PAGES/status.lua index 0731809c..d5926925 100644 --- a/src/SCRIPTS/RF2/PAGES/status.lua +++ b/src/SCRIPTS/RF2/PAGES/status.lua @@ -17,6 +17,13 @@ local fcStatus = {} local dataflashSummary = {} local erasingDataflash = false local editing = false +local help = {} +local t = rf2.i18n.t + +help = { + title = t("STATUS_Help_title"), + msg = t("STATUS_Help_text") +} local startEditing = function(field, page) editing = true @@ -32,57 +39,57 @@ local endRateEditing = function(field, page) mspSetProfile.setRateProfile(field.data.value) end -fields[1] = { t = "Current PID profile", x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { value = nil, min = 0, max = 5, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endPidEditing } -fields[2] = { t = "Current rate profile", x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { value = nil, min = 0, max = 5, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endRateEditing } +fields[1] = { t = t("PAGE_Status_PID_Profile"), x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { value = nil, min = 0, max = 5, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endPidEditing } +fields[2] = { t = t("PAGE_Status_Rate_Profile"), x = x, y = incY(lineSpacing), sp = x + sp * 1.17, data = { value = nil, min = 0, max = 5, table = { [0] = "1", "2", "3", "4", "5", "6" } }, preEdit = startEditing, postEdit = endRateEditing } incY(lineSpacing * 0.25) -fields[3] = { t = "Real-time load", x = x, y = incY(lineSpacing), sp = x + sp, data = { value = 0, scale = 10, unit = rf2.units.percentage }, readOnly = true } -fields[4] = { t = "CPU load", x = x, y = incY(lineSpacing), sp = x + sp, data = { value = 0, scale = 10, unit = rf2.units.percentage }, readOnly = true } +fields[3] = { t = t("PAGE_Status_Real_Time_Load"), x = x, y = incY(lineSpacing), sp = x + sp, data = { value = 0, scale = 10, unit = rf2.units.percentage }, readOnly = true } +fields[4] = { t = t("PAGE_Status_CPU_Load"), x = x, y = incY(lineSpacing), sp = x + sp, data = { value = 0, scale = 10, unit = rf2.units.percentage }, readOnly = true } incY(lineSpacing * 0.25) -labels[1] = { t = "Arming Disabled Flags", x = x, y = incY(lineSpacing) } +labels[1] = { t = t("PAGE_Status_Arming_Flags"), x = x, y = incY(lineSpacing) } labels[2] = { t = "---", x = x + indent, y = incY(lineSpacing), bold = false } incY(lineSpacing * 0.25) -labels[3] = { t = "Dataflash Free Space", x = x, y = incY(lineSpacing) } +labels[3] = { t = t("PAGE_Status_Dataflash_Free"), x = x, y = incY(lineSpacing) } labels[4] = { t = "---", x = x + indent, y = incY(lineSpacing), bold = false } -fields[5] = { t = "[Erase]", x = x + indent * 7, y = y } +fields[5] = { t = t("PAGE_Status_Erase"), x = x + indent * 7, y = y } local function armingDisableFlagsToString(flags) - local t = "" + local s = "" for i = 0, 25 do if bit32.band(flags, bit32.lshift(1, i)) ~= 0 then - if t ~= "" then t = t .. ", " end - if i == 0 then t = t .. "No Gyro" end - if i == 1 then t = t .. "Fail Safe" end - if i == 2 then t = t .. "RX Fail Safe" end - if i == 3 then t = t .. "Bad RX Recovery" end - if i == 4 then t = t .. "Box Fail Safe" end - if i == 5 then t = t .. "Governor" end - if i == 6 then t = t .. "RPM Signal" end - if i == 7 then t = t .. "Throttle" end - if i == 8 then t = t .. "Angle" end - if i == 9 then t = t .. "Boot Grace Time" end - if i == 10 then t = t .. "No Pre Arm" end - if i == 11 then t = t .. "Load" end - if i == 12 then t = t .. "Calibrating" end - if i == 13 then t = t .. "CLI" end - if i == 14 then t = t .. "CMS Menu" end - if i == 15 then t = t .. "BST" end - if i == 16 then t = t .. "MSP" end - if i == 17 then t = t .. "Paralyze" end - if i == 18 then t = t .. "GPS" end - if i == 19 then t = t .. "Resc" end - if i == 20 then t = t .. "RPM Filter" end - if i == 21 then t = t .. "Reboot Required" end - if i == 22 then t = t .. "DSHOT Bitbang" end - if i == 23 then t = t .. "Acc Calibration" end - if i == 24 then t = t .. "Motor Protocol" end - if i == 25 then t = t .. "Arm Switch" end + if s ~= "" then s = s .. ", " end + if i == 0 then s = s .. t("ARMING_DISABLED_NO_GYRO") end + if i == 1 then s = s .. t("ARMING_DISABLED_FAIL_SAFE") end + if i == 2 then s = s .. t("ARMING_DISABLED_RX_FAIL_SAFE") end + if i == 3 then s = s .. t("ARMING_DISABLED_BAD_RX_RECOVERY") end + if i == 4 then s = s .. t("ARMING_DISABLED_BOX_FAIL_SAFE") end + if i == 5 then s = s .. t("ARMING_DISABLED_GOVERNOR") end + if i == 6 then s = s .. t("ARMING_DISABLED_RPM_SIGNAL") end + if i == 7 then s = s .. t("ARMING_DISABLED_THROTTLE") end + if i == 8 then s = s .. t("ARMING_DISABLED_ANGLE") end + if i == 9 then s = s .. t("ARMING_DISABLED_BOOT_GRACE_TIME") end + if i == 10 then s = s .. t("ARMING_DISABLED_NO_PRE_ARM") end + if i == 11 then s = s .. t("ARMING_DISABLED_LOAD") end + if i == 12 then s = s .. t("ARMING_DISABLED_CALIBRATING") end + if i == 13 then s = s .. t("ARMING_DISABLED_CLI") end + if i == 14 then s = s .. t("ARMING_DISABLED_CMS_MENU") end + if i == 15 then s = s .. t("ARMING_DISABLED_BST") end + if i == 16 then s = s .. t("ARMING_DISABLED_MSP") end + if i == 17 then s = s .. t("ARMING_DISABLED_PARALYZE") end + if i == 18 then s = s .. t("ARMING_DISABLED_GPS") end + if i == 19 then s = s .. t("ARMING_DISABLED_RESC") end + if i == 20 then s = s .. t("ARMING_DISABLED_RPM_FILTER") end + if i == 21 then s = s .. t("ARMING_DISABLED_REBOOT_REQUIRED") end + if i == 22 then s = s .. t("ARMING_DISABLED_DSHOT_BITBANG") end + if i == 23 then s = s .. t("ARMING_DISABLED_ACC_CALIBRATION") end + if i == 24 then s = s .. t("ARMING_DISABLED_MOTOR_PROTOCOL") end + if i == 25 then s = s .. t("ARMING_DISABLED_ARM_SWITCH") end end end - if t == "" then t = "-" end - return t + if s == "" then s = "-" end + return s end local function getFreeDataflashSpace() @@ -101,6 +108,7 @@ return { labels = labels, fields = fields, readOnly = true, + help = help, timer = function(self) if rf2.mspQueue:isProcessed() then @@ -132,7 +140,7 @@ return { onClickErase = function(field, self) erasingDataflash = true - rf2.setWaitMessage("Erasing...") + rf2.setWaitMessage(t("MSG_Erasing")) mspDataflash.eraseDataflash(self.onErasedDataflash, self) rf2.lcdNeedsInvalidate = true end, diff --git a/src/SCRIPTS/RF2/pages.lua b/src/SCRIPTS/RF2/pages.lua index b86e3c50..bf99db10 100644 --- a/src/SCRIPTS/RF2/pages.lua +++ b/src/SCRIPTS/RF2/pages.lua @@ -27,44 +27,44 @@ local SYMBOL = { } -- Rotorflight pages. -PageFiles[#PageFiles + 1] = { title = t("PAGE_Status", "Status"), script = "status", icon=SYMBOL.STATUS } -PageFiles[#PageFiles + 1] = { title = t("PAGE_Rates", "Rates"), script = "rates", icon=SYMBOL.RATES } -PageFiles[#PageFiles + 1] = { title = t("PAGE_Rate_Dynamics", "Rate Dynamics"), script = "rate_dynamics", icon=SYMBOL.ADVANCED } -PageFiles[#PageFiles + 1] = { title = t("PAGE_PID_Gains", "PID Gains"), script = "profile_pids", icon=SYMBOL.PID } -PageFiles[#PageFiles + 1] = { title = t("PAGE_PID_Controller", "PID Controller"), script = "profile_pidcon", icon=SYMBOL.PID_CONTROLLER } -PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Various", "Profile - Various"), script = "profile_various", icon=SYMBOL.MAINROTOR } -PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Rescue", "Profile - Rescue"), script = "profile_rescue", icon=SYMBOL.RESCUE } -PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Governor", "Profile - Governor"), script = "profile_governor", icon=SYMBOL.GOVERNOR } -PageFiles[#PageFiles + 1] = { title = t("PAGE_Servos", "Servos"), script = "servos", icon=SYMBOL.SERVOS } -PageFiles[#PageFiles + 1] = { title = t("PAGE_Mixer", "Mixer"), script = "mixer", icon=SYMBOL.MIXER } -PageFiles[#PageFiles + 1] = { title = t("PAGE_Gyro_Filters", "Gyro Filters"), script = "filters", icon=SYMBOL.FILTERS } -PageFiles[#PageFiles + 1] = { title = t("PAGE_Governor", "Governor"), script = "governor", icon=SYMBOL.GOVERNOR } -PageFiles[#PageFiles + 1] = { title = t("PAGE_Accelerometer_Trim", "Accelerometer Trim"), script = "accelerometer", icon=SYMBOL.ACCELEROMETER } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Status"), script = "status", icon=SYMBOL.STATUS } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Rates"), script = "rates", icon=SYMBOL.RATES } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Rate_Dynamics"), script = "rate_dynamics", icon=SYMBOL.ADVANCED } +PageFiles[#PageFiles + 1] = { title = t("PAGE_PID_Gains"), script = "profile_pids", icon=SYMBOL.PID } +PageFiles[#PageFiles + 1] = { title = t("PAGE_PID_Controller"), script = "profile_pidcon", icon=SYMBOL.PID_CONTROLLER } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Various"), script = "profile_various", icon=SYMBOL.MAINROTOR } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Rescue"), script = "profile_rescue", icon=SYMBOL.RESCUE } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Profile_Governor"), script = "profile_governor", icon=SYMBOL.GOVERNOR } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Servos"), script = "servos", icon=SYMBOL.SERVOS } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Mixer"), script = "mixer", icon=SYMBOL.MIXER } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Gyro_Filters"), script = "filters", icon=SYMBOL.FILTERS } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Governor"), script = "governor", icon=SYMBOL.GOVERNOR } +PageFiles[#PageFiles + 1] = { title = t("PAGE_Accelerometer_Trim"), script = "accelerometer", icon=SYMBOL.ACCELEROMETER } if rf2.apiVersion >= 12.07 then if settings.showModelOnTx == 1 then - PageFiles[#PageFiles + 1] = { title = t("PAGE_Model", "Model"), script = "model", icon=SYMBOL.FBLSTATUS } + PageFiles[#PageFiles + 1] = { title = t("PAGE_Model"), script = "model", icon=SYMBOL.FBLSTATUS } end if settings.showExperimental == 1 then - PageFiles[#PageFiles + 1] = { title = t("PAGE_Experimental", "Experimental (!)"), script = "experimental", icon=SYMBOL.MSP_EXP } + PageFiles[#PageFiles + 1] = { title = t("PAGE_Experimental"), script = "experimental", icon=SYMBOL.MSP_EXP } end if settings.showFlyRotor == 1 then - PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_FLYROTOR", "ESC - FLYROTOR"), script = "esc_flyrotor", icon=SYMBOL.FLRTR } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_FLYROTOR"), script = "esc_flyrotor", icon=SYMBOL.FLRTR } end if settings.showPlatinumV5 == 1 then - PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_HW_Platinum_V5", "ESC - HW Platinum V5"), script = "esc_hwpl5", icon=SYMBOL.HOBBYWING } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_HW_Platinum_V5"), script = "esc_hwpl5", icon=SYMBOL.HOBBYWING } end if settings.showTribunus == 1 then - PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_Scorpion_Tribunus", "ESC - Scorpion Tribunus"), script = "esc_scorp", icon=SYMBOL.SCORPION } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_Scorpion_Tribunus"), script = "esc_scorp", icon=SYMBOL.SCORPION } end if rf2.apiVersion >= 12.08 and settings.showXdfly == 1 then - PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_XDFly", "ESC - XDFly"), script = "esc_xdfly", icon=SYMBOL.XDFLY } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_XDFly"), script = "esc_xdfly", icon=SYMBOL.XDFLY } end if settings.showYge == 1 then - PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_YGE", "ESC - YGE"), script = "esc_yge", icon=SYMBOL.YGE } + PageFiles[#PageFiles + 1] = { title = t("PAGE_ESC_YGE"), script = "esc_yge", icon=SYMBOL.YGE } end - PageFiles[#PageFiles + 1] = { title = t("PAGE_Settings", "Settings"), script = "settings", icon=SYMBOL.SETTINGS } + PageFiles[#PageFiles + 1] = { title = t("PAGE_Settings"), script = "settings", icon=SYMBOL.SETTINGS } end return PageFiles diff --git a/src/SCRIPTS/RF2/ui_lvgl_framework.lua b/src/SCRIPTS/RF2/ui_lvgl_framework.lua index 81c27193..4633bc05 100644 --- a/src/SCRIPTS/RF2/ui_lvgl_framework.lua +++ b/src/SCRIPTS/RF2/ui_lvgl_framework.lua @@ -51,7 +51,7 @@ ui.showMainMenu = function() local menu = { title = "Rotorflight " .. rf2.luaVersion, - subtitle = t("TITLE_Menu_Menu", "Main Menu"), + subtitle = t("TITLE_Menu_Menu"), items = {}, back = function() ui.state = ui.status.exit end } @@ -109,9 +109,9 @@ ui.saveSettingsToEeprom = function(eepromWrite, reboot) if not ui.saveWarningShown then ui.saveWarningShown = true if rf2.apiVersion >= 12.08 then - rf2.executeScript("LVGL/messageBox").show(t("TITLE_WARNING_Save", "Save warning"), t("MSG_WARNING_Save_later", "Settings will be saved\nafter disarming.")) + rf2.executeScript("LVGL/messageBox").show(t("TITLE_WARNING_Save"), t("MSG_WARNING_Save_later")) else - rf2.executeScript("LVGL/messageBox").show(t("TITLE_Save_Error", "Save error"), t("MSG_Save_Error", "Make sure your heli\nis disarmed.")) + rf2.executeScript("LVGL/messageBox").show(t("TITLE_Save_Error"), t("MSG_Save_Error")) end ui.refresh() end @@ -127,19 +127,19 @@ ui.showPopupMenu = function() if Page then if not Page.readOnly then menu.items[#menu.items + 1] = { - text = t("MENU_Save", "Save"), + text = t("MENU_Save"), click = function() Page:write() end } end menu.items [#menu.items + 1] = { - text = t("MENU_Reload", "Reload"), + text = t("MENU_Reload"), click = function() Page:read() end } end menu.items[#menu.items + 1] = { - text = t("MENU_Reboot", "Reboot"), + text = t("MENU_Reboot"), click = function() rebootFc() end } From 726c8940cc96d2acd9909ffa3d65520ef4d79910 Mon Sep 17 00:00:00 2001 From: egonl <34315684+egonl@users.noreply.github.com> Date: Tue, 27 Jan 2026 00:32:25 +0100 Subject: [PATCH 3/3] chore: aligned with firmware (#126) * Aligned MSP_GOVERNOR_CONFIG * Aligned MSP_RC_TUNING --- bin/minimize.lua | 1 + src/SCRIPTS/RF2/MSP/mspGovernorConfig.lua | 39 +++++++++++++++-------- src/SCRIPTS/RF2/MSP/mspRcTuning.lua | 12 ++++++- src/SCRIPTS/RF2/PAGES/governor.lua | 5 +-- src/SCRIPTS/RF2/PAGES/rate_dynamics.lua | 5 +++ 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/bin/minimize.lua b/bin/minimize.lua index f9ea3fe7..22cb23b2 100644 --- a/bin/minimize.lua +++ b/bin/minimize.lua @@ -166,6 +166,7 @@ local mspRcTuningReplacements = { { ".yaw_dynamic_ceiling_gain", "[28]" }, { ".yaw_dynamic_deadband_gain", "[29]" }, { ".yaw_dynamic_deadband_filter", "[30]" }, + { ".cyclic_ring", "[31]" }, } local mspPidTuningReplacements = { diff --git a/src/SCRIPTS/RF2/MSP/mspGovernorConfig.lua b/src/SCRIPTS/RF2/MSP/mspGovernorConfig.lua index 24835fc4..707b6411 100644 --- a/src/SCRIPTS/RF2/MSP/mspGovernorConfig.lua +++ b/src/SCRIPTS/RF2/MSP/mspGovernorConfig.lua @@ -12,7 +12,9 @@ local function getDefaults() defaults.gov_throttle_hold_timeout = { min = 0, max = 100, scale = 10, unit = rf2.units.seconds } if rf2.apiVersion < 12.09 then defaults.gov_lost_headspeed_timeout = { min = 0, max = 100, scale = 10, unit = rf2.units.seconds } - defaults.gov_autorotation_timeout = { min = 0, max = 600, scale = 10, unit = rf2.units.seconds } + end + defaults.gov_autorotation_timeout = { min = 0, max = 600, scale = 10, unit = rf2.units.seconds } + if rf2.apiVersion < 12.09 then defaults.gov_autorotation_bailout_time = { min = 0, max = 100, scale = 10, unit = rf2.units.seconds } defaults.gov_autorotation_min_entry_time = { min = 0, max = 600, scale = 10, unit = rf2.units.seconds } end @@ -28,10 +30,9 @@ local function getDefaults() defaults.gov_d_filter = { min = 0, max = 250, unit = rf2.units.herz } defaults.gov_spooldown_time = { min = 0, max = 600, scale = 10, unit = rf2.units.seconds } defaults.gov_throttle_type = { min = 0, max = 3, table = { [0] = "NORMAL", "OFF_ON", "OFF_IDLE_ON", "OFF_IDLE_AUTO_ON" } } - defaults.gov_idle_collective = { min = -100, max = 100 } - defaults.gov_wot_collective = { min = -100, max = 100 } defaults.gov_idle_throttle = { min = 0, max = 250, scale = 10, unit = rf2.units.percentage } defaults.gov_auto_throttle = { min = 0, max = 250, scale = 10, unit = rf2.units.percentage } + defaults.gov_bypass_throttle = { } end return defaults end @@ -49,11 +50,15 @@ local function getGovernorConfig(callback, callbackParam, data) data.gov_throttle_hold_timeout.value = rf2.mspHelper.readU16(buf) if rf2.apiVersion < 12.09 then data.gov_lost_headspeed_timeout.value = rf2.mspHelper.readU16(buf) - data.gov_autorotation_timeout.value = rf2.mspHelper.readU16(buf) + else + buf.offset = buf.offset + 2 + end + data.gov_autorotation_timeout.value = rf2.mspHelper.readU16(buf) + if rf2.apiVersion < 12.09 then data.gov_autorotation_bailout_time.value = rf2.mspHelper.readU16(buf) data.gov_autorotation_min_entry_time.value = rf2.mspHelper.readU16(buf) else - buf.offset = buf.offset + 4*2 + buf.offset = buf.offset + 2*2 end data.gov_handover_throttle.value = rf2.mspHelper.readU8(buf) data.gov_pwr_filter.value = rf2.mspHelper.readU8(buf) @@ -69,14 +74,17 @@ local function getGovernorConfig(callback, callbackParam, data) data.gov_d_filter.value = rf2.mspHelper.readU8(buf) data.gov_spooldown_time.value = rf2.mspHelper.readU16(buf) data.gov_throttle_type.value = rf2.mspHelper.readU8(buf) - data.gov_idle_collective.value = rf2.mspHelper.readS8(buf) - data.gov_wot_collective.value = rf2.mspHelper.readS8(buf) + buf.offset = buf.offset + 2 data.gov_idle_throttle.value = rf2.mspHelper.readU8(buf) data.gov_auto_throttle.value = rf2.mspHelper.readU8(buf) + data.gov_bypass_throttle = {} + for i = 0, 8 do + data.gov_bypass_throttle[#data.gov_bypass_throttle + 1] = rf2.mspHelper.readU8(buf) + end end callback(callbackParam, data) end, - simulatorResponse = { 2, 200, 0, 100, 0, 20, 0, 20, 0, 30, 0, 10, 0, 0, 0, 0, 0, 50, 0, 10, 5, 10, 0, 10, 5, 0, 30, 0, 0, 161, 246, 0, 0 } + simulatorResponse = { 2, 200, 0, 100, 0, 20, 0, 20, 0, 50, 0, 0, 0, 50, 0, 0, 0, 0, 0, 20, 5, 10, 0, 5, 0, 50, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } rf2.mspQueue:add(message) end @@ -95,14 +103,16 @@ local function setGovernorConfig(config) rf2.mspHelper.writeU16(message.payload, config.gov_throttle_hold_timeout.value) if rf2.apiVersion < 12.09 then rf2.mspHelper.writeU16(message.payload, config.gov_lost_headspeed_timeout.value) - rf2.mspHelper.writeU16(message.payload, config.gov_autorotation_timeout.value) + else + rf2.mspHelper.writeU16(message.payload, 0) + end + rf2.mspHelper.writeU16(message.payload, config.gov_autorotation_timeout.value) + if rf2.apiVersion < 12.09 then rf2.mspHelper.writeU16(message.payload, config.gov_autorotation_bailout_time.value) rf2.mspHelper.writeU16(message.payload, config.gov_autorotation_min_entry_time.value) else rf2.mspHelper.writeU16(message.payload, 0) rf2.mspHelper.writeU16(message.payload, 0) - rf2.mspHelper.writeU16(message.payload, 0) - rf2.mspHelper.writeU16(message.payload, 0) end rf2.mspHelper.writeU8(message.payload, config.gov_handover_throttle.value) rf2.mspHelper.writeU8(message.payload, config.gov_pwr_filter.value) @@ -118,10 +128,13 @@ local function setGovernorConfig(config) rf2.mspHelper.writeU8(message.payload, config.gov_d_filter.value) rf2.mspHelper.writeU16(message.payload, config.gov_spooldown_time.value) rf2.mspHelper.writeU8(message.payload, config.gov_throttle_type.value) - rf2.mspHelper.writeU8(message.payload, config.gov_idle_collective.value) - rf2.mspHelper.writeU8(message.payload, config.gov_wot_collective.value) + rf2.mspHelper.writeU8(message.payload, 0) + rf2.mspHelper.writeU8(message.payload, 0) rf2.mspHelper.writeU8(message.payload, config.gov_idle_throttle.value) rf2.mspHelper.writeU8(message.payload, config.gov_auto_throttle.value) + for i = 0, 8 do + rf2.mspHelper.writeU8(message.payload, config.gov_bypass_throttle[i + 1] or 0) + end end rf2.mspQueue:add(message) end diff --git a/src/SCRIPTS/RF2/MSP/mspRcTuning.lua b/src/SCRIPTS/RF2/MSP/mspRcTuning.lua index 4573480a..82941ae4 100644 --- a/src/SCRIPTS/RF2/MSP/mspRcTuning.lua +++ b/src/SCRIPTS/RF2/MSP/mspRcTuning.lua @@ -40,6 +40,10 @@ local function getDefaults() defaults.yaw_dynamic_deadband_filter = { min = 0, max = 250, scale = 10, unit = rf2.units.herz } end + if rf2.apiVersion >= 12.09 then + defaults.cyclic_ring = { min = 0, max = 250 } + end + defaults.columnHeaders = { "", "", "", "", "", "" } return defaults @@ -97,9 +101,12 @@ local function getRcTuning(callback, callbackParam, data) data.yaw_dynamic_deadband_gain.value = rf2.mspHelper.readU8(buf) data.yaw_dynamic_deadband_filter.value = rf2.mspHelper.readU8(buf) end + if rf2.apiVersion >= 12.09 then + data.cyclic_ring.value = rf2.mspHelper.readU8(buf) + end callback(callbackParam, data) end, - simulatorResponse = { 4, 18, 25, 32, 20, 0, 0, 18, 25, 32, 20, 0, 0, 32, 50, 45, 10, 0, 0, 56, 0, 56, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 60 }, + simulatorResponse = { 4, 18, 25, 32, 20, 0, 0, 18, 25, 32, 20, 0, 0, 32, 50, 45, 10, 0, 0, 56, 0, 56, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 60, 150 }, } rf2.mspQueue:add(message) end @@ -144,6 +151,9 @@ local function setRcTuning(data) rf2.mspHelper.writeU8(message.payload, data.yaw_dynamic_deadband_gain.value) rf2.mspHelper.writeU8(message.payload, data.yaw_dynamic_deadband_filter.value) end + if rf2.apiVersion >= 12.09 then + rf2.mspHelper.writeU8(message.payload, data.cyclic_ring.value) + end rf2.mspQueue:add(message) end diff --git a/src/SCRIPTS/RF2/PAGES/governor.lua b/src/SCRIPTS/RF2/PAGES/governor.lua index 0f02e8df..eb6c4785 100644 --- a/src/SCRIPTS/RF2/PAGES/governor.lua +++ b/src/SCRIPTS/RF2/PAGES/governor.lua @@ -23,16 +23,13 @@ if rf2.apiVersion >= 12.09 then fields[#fields + 1] = { t = "Handover throttle", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_handover_throttle } fields[#fields + 1] = { t = "Throttle Hold TO", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_throttle_hold_timeout } incY(lineSpacing * 0.5) - labels[#labels + 1] = { t = "Throttle Curve", x = x, y = incY(lineSpacing) } - fields[#fields + 1] = { t = "Coll -> Idle", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_idle_collective } - fields[#fields + 1] = { t = "Coll -> Full", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_wot_collective } - incY(lineSpacing * 0.5) labels[#labels + 1] = { t = "Ramp Time", x = x, y = incY(lineSpacing) } fields[#fields + 1] = { t = "Startup time", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_startup_time } fields[#fields + 1] = { t = "Spoolup time", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_spoolup_time } fields[#fields + 1] = { t = "Spooldown time", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_spooldown_time } fields[#fields + 1] = { t = "Tracking time", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_tracking_time } fields[#fields + 1] = { t = "Recovery time", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_recovery_time } + fields[#fields + 1] = { t = "AR timeout", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_autorotation_timeout } incY(lineSpacing * 0.5) labels[#labels + 1] = { t = "Filters", x = x, y = incY(lineSpacing) } fields[#fields + 1] = { t = "HS filter cutoff", x = x, y = incY(lineSpacing), sp = x + sp, data = governorConfig.gov_rpm_filter } diff --git a/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua b/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua index 655b3f48..48101c28 100644 --- a/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua +++ b/src/SCRIPTS/RF2/PAGES/rate_dynamics.lua @@ -74,6 +74,11 @@ if rf2.apiVersion >= 12.08 then fields[#fields + 1] = { t = "Deadband filter", x = x + indent, y = incY(lineSpacing), sp = x + sp, data = rcTuning.yaw_dynamic_deadband_filter } end +if rf2.apiVersion >= 12.09 then + incY(lineSpacing * 0.5) + fields[#fields + 1] = { t = "Cyclic ring", x = x, y = incY(lineSpacing), sp = x + sp, data = rcTuning.cyclic_ring } +end + local function receivedRcTuning(page) rf2.onPageReady(page) end