From 8f47b2e7e3ffa8e0f72362f9f9c6426c073839f7 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Tue, 7 Jun 2022 23:56:13 +0900 Subject: [PATCH 001/116] Screenshot : move a path --- screenshots/watchface_analog_osw.png | Bin 0 -> 53909 bytes .../watchface_binary_osw.png | Bin screenshots/watchface_digital_osw.png | Bin 0 -> 52295 bytes watchface_analog_osw.png | Bin 79193 -> 0 bytes watchface_digital_osw.png | Bin 77980 -> 0 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 screenshots/watchface_analog_osw.png rename watchface_binary_osw.png => screenshots/watchface_binary_osw.png (100%) create mode 100644 screenshots/watchface_digital_osw.png delete mode 100644 watchface_analog_osw.png delete mode 100644 watchface_digital_osw.png diff --git a/screenshots/watchface_analog_osw.png b/screenshots/watchface_analog_osw.png new file mode 100644 index 0000000000000000000000000000000000000000..d7aa8eeb4bed90b54c02e814047113227d9ca3e1 GIT binary patch literal 53909 zcmXuL1wfPS|2;e;rMtW3L1IXEca2d}0s{mAX{3>oPATbTG$<$`C5@Cwiy$H0CH=qn z{@(ZIMsyq3uK46RXGZC0DdS;NV?!ViJXIA17zBcn`S6W}0Uj|a(HI3k(ClP2Wg(FI z1e_a7bntIRYZaI#1mepMfdq#^AXng_;7tg`lMe#fegT1qWk4VlF4--*65t68D|KZB z$o<1t{@1b;@W^8q6=Qb@1c&6|8wK(qn-V;T>7lBri1`(b^=2Ld5qbP0MNB@NT zW}ibY`1>}Siw`=xKfcMcG3G7W_}qTr24T2qw772cTL_>dA}45F#EYy$v}N<32acU= zUKm`#I7lH7Ysdcr%AnaN#t<3^t@DMV!lve%TsxDr)b4J9&-(uKNR6DA;KjoY%Rcm! z*2~!&^8t87X&99cgFSN@#mRQZJhU({Yc5@4eykW-7xHENQ;IwO*vXAuJx_S3`#xWv zS7YlDQCdVKqJ=W=^1B@@w%!}HF6u>hqLKnPkpa;w$uYlZ_GicLTq;6$DBUOa?xSO` zFVGc?sF{3z4nFR+$74yxrL@pNCnCqHWu!iXougyfYmdZ= zQC5I1#<`1b_!#f8kwkq-u#HW#5quva!SWy(DDKg~^4*6E+FshPRyi3UBM?0;E}mmR(I+xqPIlj3uX&UbPa zRrc;^Id+o1jA@>t`U!<(4GI?K%>8h@7jY`wi0|op0$g9cZ*8PHMH5&vvHpunDg48L zbshqLKX;co=5JfKNI`7r3g)5SCCbp%je`p*6xNd8eOskOGCZ>r_3$eZEk%QRD@}Y6 zLH5@?eY5di7V2TWOyE6w$ssg&uxRLboQ|}!3G1MOk!mE*aLWe#m$FSsfX}E;#p2BW z4esaqR)abDmD@L|d0yt|q^P!?Ld2y$aOk4MfY!;a|_jq(*(- zo0sAcEq>bX`H$(Bc&Z&0lLGwAxSEFsT&EJeHVfxhM%-y@*?BKw@%pUlNv(I?MlWSY zeTEvUb|5_{zX+D0qnDCr@KgNYww)GyYsZfpKGGZ6b`oRa&I{)nB{0?Ink;G8m9WYE zS9`1jW5t6)ddea0?L?g(tqb%8f(opYIkV`Uy>eWq7+<{;u{G0w6jAUC38gh~zxrrn zoNB}^^wM~m&)TubY2l!W`&EaHF-w{a9<&d`Y2o+d7e5-fv-rVlhrv^I=K9U;hvX2E zv%vf6E4$|3={9307$O_LP9#P}gSt=JBsOj&W;}zQNl5rdZTKv?n0cqHidg*3uDy^r zP|n@x71>bcU}yJD4%@c3$@kT=dED2)J?UXFZVFfFSuud2oHLjnjN9GstStF z=7Eq-jaJ^5PmDSOZ&k!{%o$>Oy?U+cnS*g07o?=gW6TH>`rkP%jLtQEoojL;kLjfy zZrC;AZdz#I?y=%GN<;6XpfPHGVy=*<05A@n_$E%!-91 zO|??bo*88xG=gyW=^?=2=G~o^VWMOcbXpXWk9U;2Q4?(S{{GwIY=|6IQc`k@QdrqG z;wDe%U!|CBy8ZJ;Lds#`T!A@>GOB+ywBG1D_|fFF5ZP-5O`7$%wTeI^Qh*-kb6y~a z;`5Cb>jyVSM73Q<^=fwTeRDrgcrKbXKF6!sxjT4X9r3)nkFFm%<fAg{P69r+>1e$|jO#i04w$A3t=$)c%C8*;l?BhM+nY>z?t^IieMGWG zr1nI#N@2)f`z`w^jnAvCouqyW7h_NE%_PNqayqWP+pcx%xZCN-eSP7nh?M{~m>?93 zD5La)*`&9n?bqr>3Kr|tzPK!>1#`QFb3r70`}6A2KMm%jFN~QQf0GA`=@R;NIZ|bl zVIGJ=X3T90y;6tzD*x=+JXv+~VG>B@z-FtBu~fm}g^Et|I&J@8bB$j>vuS%fm?)Ul zb0nPpN%}Aq2RiTZ*UQ5QGKYvWca@xgG)y#kqJFAw!tdVf891ZqG z1k|2`_;JswYh;+*jAb%x?d>9KTx0+R>t#7By*^`s!+DKf?G_f6j6B^Sf;e}BDQl$r zL_#F~8*TrbJ`%2jgg2!Pug~anrQVD4@g1608(iPQkf*F0H{)w-h=pQWkfY6r4XI?Q zo={pVj{1;#P1u0Ye0@lqedL18&5a+%d8{Fj-WP3-9R=WN9G zW4Smf?u>)r`{DJN|5ArOtCjpna%gPfO&`Af0ycM8RQj|VhxdEc->-kO^WN8Xok$c( zDzR-%O|^*j%~nI`%|~8=3=bkgz?bZh9||ivUB%GKAo_8-)?c%Amfv3Rq__4qRE>Z` zzw!_ZkY!JydS6181n(wPPTW>!>y28_Po{S=MAp6ZOH|Wh>(vS1YM5v)s4Rxdag(25 zI`&bn9Ere?q|i*=KJE$tvN^cU_rooup!ZwJ3{?^@`p+Io0+xO1iYHaab2=^=j} zAU+y%9B*&WUm!JIR6d?$uap7 z7|I51{A&Jw;cgH`++_=jfp>?;Ipe6Pg4Ir8Ao|38Hs|u zHB&*E&G&nv*|FXg?+7*e8+q@!Gd%~KC*qC7-K$IuTW@gmLRoYm$EdIpBR;)OG(d=} zC-x8{+R9LJS&I~y|D>R)YBo7tBjom&8j|piS{UUf1Wott#!fy&mKjubxzfHLwh@V6 zy(fASwE>s4sU&g|TVa*kWnun~fU1UltC-qu43|RzD^NzluYv?JzdNnFU1Byq-`iUM z^e0k?>N1mb0ok%-wS=><^zUKEFS-Z<`HuN^h{607%gd%j&>8ja@$z+@N?EAmia$Cg ze+Oa9PoFtyHchSM&X7ID_2b;Gi&&1vx;*K(OQ~v#bL91!R#`Tl+1Yb%ucC^x zHP}O+R|^4W)8!<+YtZ4O1>U^wA$I$&*XoEuPft(%d<7;MbnKlPt;;dxGAaOxKml`R zd$65O%GOMGDUA;O2$;T3sfLnVfJ=6X=5t}Ec@G=0oV#HUF(2pTG7lZaM^VS`V$DSCzJZ8c2e_XvY4d zFh51Ll=z9jB>)#L?u`L7^G3VbG~N!HndB(+iljcWrcca@r~nokRSYw11`&)oQ{yT* zNv)8dDs5f+(zN9ZWj*~=bI+BA4g4Bzqac{4(h$G;k661vN2cEBRR48LQ#69zqVg9- zlM_p-T0w0suOJ^^U6BswE+;AW0WW#Xk`^m5s08jl+U5F`vNa&{Hsn&?=C$>QwB2kk zVWN0=p}B@(Je)vzS;}0*m1K%OLX0fRnX&SqXg%Go`;#R|Cf`6nDcbV5%4s$o9kTrx zTAZ7_#|`;_yUm4E%pUn6lde@ZF*5_)Zc>H|y7uyO>eb>=c^vu;h(_y9mzJ<(gfJNa2zr%Og25Pl9KtmGFTJ z#!31+Z){^YT<#CcMvnJyX%IZ6^D;89$PNcZErvny-ibdIkXWnBk*R*+;hy2Hyon3e zBdOv#n&3L>{b+pt1=ew=J+(w=ozKZ%Cy=u*pqbx!fhEB$EG)QE)dW>Z8=fkD3M~&I zkK&x%de$(N)Q*geS)`5FN=pg|oP?5a zXlbBJNO9-~u-zHVk?JpnKOQ_!qhH2yQdEGNJsQ3A9la#Ks-`gwU6EeXe{6Zkv(VzX z0}_p}4K&mH;_S>UWq2Kigby+NDmTyJx7ff_9EF62hHmcc$U`$7Rc}jZKJ^@MJ=XqR zTPg3{s?})2%-%f8cwsirlajZ81EnH*Qaou7Zd`o)E7<7nF8A@J1a^4H`5e&>xmm4Z zH&Ps@80>rNx={_dutKec|BfB z*Yp}0dz$Xnv1W3Jnm(BVp)4#+RgwMmjH*J*j&P&;uiEG5vNz7gX$KPZUVG1%;spc* zLj9#`9i=tR6_T0k!+w77Y-on&jRo=KXdPIzdhNAuZEbakx~}w$J<4s3XlJz2v#HZL zox%#vLfKUgi+|{{LoF~9VR+C&U#5X9Rf*F0x0SW+zI8C<&4Gv5SAHIzzs(Pk^NKq@4e>I#&M2A4V=PBL2vSm0%ZcTjI|*6Q^ti|9;6+#t{$Sl2 zI2#DH(V_9^-;`+b@CiR6T1(N+ZQCr2aeHQ&w7^*Tx97Z~=41QFU%D?E zifDoc9O71CY=89fu72j*7>~J*V)k~aZ*+494F$d5M+64`7Ij<0s+g+4dq%zS_Ai$I zT=|%2e`hBII21o0-}tga6}7*oLwhe{)h+u#(SNw2TiZ}G!$eIET&C@LA~ZV7!I?t! znjz5(It;BmsW`cUWsBDA7A3__w6T*!4R+W4<_+fbVZq`-GRRN&K?=(z!w~O{SeB9z%cqJ2&vQmI(W%>{ohec5&24@pwI@tA zaYsCrg}3p~A4}kO*&?owfcXwx^)yA!SS<*d&M1Q1B$VZ}Z9zx0&1$lhtAR4Wq{cgW z1k$6p3w-^@hNch4VDdQ30lL9A=co9+~pu&|hoJmUt@2`yHQCa!qL<3^+L;R~Z>KRPo za6MjA6^SqM=t-=lfnbL}qV0d1VIJ|*sqj7XzCeNbfyyl}rxu4?)&tzM%yz11kc#qm zu8s4_`0HrWyu7>%Lz8Dr^a<8`^Np1B^yh=&+t3lAZ^ZAS{5_WRiD8M0a)O)~ssdu3 zI*A^|l>#a@hX*(Iheuu18C{P>ZQ zh9-2U1+rZE9e$xMkr%~Szl=um^u;v#|F(x(XDoZYQ*dh6ylHiuQHLv)I)rO0i_W5M+~jGI(lX?x=f$aB*uQ6Vz{Z|hX4{w|17JR!8J(7;=?(nYI5lv z;X=wF!UfoiP@-nzb0^OKq+X}0_2$h+3Q;y!ZArz<=r7r!ioC_518t-j?dPSyYeuv& z=!8gZL+F5j!jZ7eg-tBzPOY4s@#h?y>>--$DQa%IOtICnVOoM5fdnw3t@(n5+7y3; zm4371jzJe(6h08-27{$8%I)J!y-qf=UvoJ9%O8UC*(d6R1*_nYHmo6?CJ1flB!q1Y z3yE8D#&N);Mx(vHdL#lc1b?^3P;=D3RILt&$qT&G1ueOZ)}Qx3s}QafBA`j-k5n~@ zRT3Sv1;4}~SZY2z!4Rv!J!a>C&~=x$hx~kLWt_ql-%c`DWzj+3A5Zt~^z@lpNwP%^ zoJ;VFym)-*8;P1WA=j+Iug!tq`?LeL^_rJ%MwVh@@9AQ}wlUa4RAml6RKP?B7(LPH z1jNO6TA_AOs)x~brmN+}at!dfE0)-^5}ivmIy{LDgQJVLS`-@cKMAko4bIkvs!|Ii zebA~XYH}H+S$VhlhMDTBYRUm`!2`|FL3?(|vc@711HPtAZ=WUnx^G|ri=Bf5k~%O)cJ*^@s;TERxnw3{VnEq{ zbFJ_rVO6C4)Y?rRU%k{am*MiNTO~D?pEX6*aj}IA#Cj3mQ_j-T(!{Y1n)s4+td*lL zKjL4ucy|lpKAOc^)+vvPA14P@+2w4ZUO~BSdPM_(HoCs-`_KdDY;v3niK7v|swt7J z;F@gb<6=*_Rr01C@p1yK9T{0j?6laK8D*qH7T*l_MbaRNCI{7g)1JEYAmWF#bP~R5 znJgE)nE-yy)Vx^nivKLm!33JwllIhvPf&2Zby$xcpl}Y2&%ZtLmMMBA5X?TNf=s|b zX~XRNTHtII)&#NmT=2MEUnt;g5Z)iZ136syOXz`q> zW)VxJ*73%x7>qXxyuCUT0oefrN#>-N$#sg?v1%dMvlKr6cV>>okY`WFi$C@gs*K3( z^pHd%KwU=L-__X}Jb}fqCiJRdWPo1QZE-~?Sqtp2Hh1-`PLI%bFD5w1Gxi1-!0pSMZO{zmM(PU>ih931xEUQd^sf5N?Gt8h?-ukxwR@uvM zYQ!Jew%zJr!cAU8M)6SmoASIvKI8>qr0Kkq&%35h5CmYwx8 z8VSb+rGG#`K>j*4JSIH+C|^J{cwFd`D)Anm4nMX$z7^VANh(A(C~#hUbr9e1?+547 z-dsXMW2sN13eAZ#%RaG=t&igp4BMo~c~&um5XYt4@uAns7J1v%C0jiq7@H$kBKJ6% zv}ZkJkR*1VEqCVGH34%&zEI4P{*N@ZXq;6HM;OP}Hh(ISey&ws`L3+kV?~4NDF;E& zj*Amzu+lV3it&o2U^4j(0Pvy8cvvID5W2!552^yrt>dc`S z1QmiNX@LT5ao5D=JAp}_Mx@xm7lSCB4LGB7dZ@%V^PqrB#G0EZ0!qb792IfRXy=ib z@cK;59&9%lmxfPRc;5Jdw)pE?Icw;ymqLU```foD7RhR?#F}H7 z(ISydd?f`aU9@)KaY`tp38l+kX)^`R1XmJdc}gDB{ySHO3onOB zntLwM0rXhU<_tm{IV^u=_MQxddJ+1R$M(rOcT~JG@TowTWf#3PN|}%>r)$}nNli^4 zNr!pS_H)prQX62-3=NMX`$a4wR~b>Is-x#B>Lp{JhBcu#-&9;F+f8D- z^XO;t_4(wOxc?WASK-8EuP02zzn()fob=96C`&OYNE(`{Auo|UN?r=1iLNlYqEG1O zfA(x`Luk^BL3Q=h`{1o#-3Oloj#Ki!Gs!74GiQ#5$FxW)1LGu-VZGGd*ec!!p3Y?Gq! z+^`D2N}3xJdvVob5Cbo?NTy6m&xaIv77js`@D7YzP0DGm4dA2aB&vdg6)BrU+*Qq_ z1*i{+bj1b|u^xAfqm2C78?4?ep(+UQ@{^MjP&2>0gq!e4~YPV+H%&>vB+m(am)N&ot45P#SlRQ#dIlP-Xv zIkX2iyI5Xk1bI{!R%$&ctH^da7*7yeuTB_eLl?8z=fT6}$RwQNH9a8uI^$@T#g`Q)&vcX=*6vroW5EVCoVuz?8nXwypySn`I+Cg<+U->pJb4~uLN%M4m1D9t3 z^0z_Tn1>U4!{EAGphU`co0vWo6Npl1Q5c%hrZY~y?Sf8rkl(Z|?krVY%-@1GR=#Ds zzjNPT0+9Vne$E`jw6>>tW7lX*X-rWn8h@Da9|3e?5Yg}?v~HGs%G*pMJUc|6Q4+AL)%MY`#bE6 z>{whA`%jH$&e5Rt?w$P$T~(15H!b^b08KFflJ%-J; zuOahv)Arq;=ww0>EK)R9OUV6u&~QZeTBXE%9jy=J|C^GDA{4Buu&Dxa@Y`|%^2y_6 z&e46Y)aZ%G8YuS0iI22YA7YYlFua%|N7ih8g#EMOT}{jHx^3QOsZ^Tk3SN(e?pYs= z4MVe-eM*wdif!C&fvL;qosIEK5AuiWSp7mWW0z-t72Tu;fn zSyOot%2Fi;suCGMJ@fUwPr3t0t|^c3dje(}$Q|{rTYeUnn<9H?Afd-7N=p+uRe^q} zBV}XSEXL&J`d-U9nvYiI(1+r0jH!l{6!tl4JXI7~rtDQaU!ow2S$LWn9$f7R=oT+3 zk45DT$7j9wzsdH#kawcLrC_j}0!D9VB~Cs)^b+Fpix8eG*^*hm(*n%>6(a$cHdUhM z8nJDs-Yv%Xnvbnq;!mcTddh{+C^Qc*q9bkdYN(37eT6`IPK8$`t6IGoS3gcOkEp}% zV%y27f)i(wJQik}dhY5t`Iy=$&kTv*13T4VSyhMF|6qE!Ni^;co{x`ay(oRu@jC}x&E&__zm1bEY zboG8I^va8(Gxcp;T-|nL+prj6_6gudKkh8u8d0jf(^}A1kT(}!!O^%xVqjq0Op)7M z%K+$TzVswFxddfW1_6CmSxlOep60*!pDjv)2K_y3pE2@1A-YmteFWjNLBi`v z#79^!OL!)22D>nbL>$D;7Vgcoe>XN7_h(B*sG|#>q^f~AS(!LOI83(xVO55xByaKk zoV5NY0EH0^w7k6REqN=e@r!d5pj8TwL2zgN9H8_naRPf7*H z<{SM0+3h?&E*bsn5J&zBp^O??yKw?}6)siQ*m*5@RwkA}WH97e`Ow;Nn$0CFe+X5x z>`Gtt{7131II{;Wusw-v)MaUiot0$|Re=@vIeh!3#i`-v zcm?(#TB@tb492BM&K1x1ddn-O0h!;?esxC5i63PWPf33|Pu&?f3RK)GK%rLkMw8w4 zVweOe3g0MCqDp@&b3jaqTC7>Bupd^|mf}udX;6vhiqi0&7_nQHo&<9rzzNqic3to3 z#n-T0F(p4)Km)8)d9~PesM@0mQOwPG# z5eU7PO0bFqMm2s})R^to3cQF{ueLsKy~%l(`VV0|ZoiYU3Sxj=}av56mD#|0YY z(8DNge`dh!nVa&YJLzweOzxTl&H0W%x z-TP}LG|2-%zo0(#goTj-q>V02uT1OKpxN}dX3bCoqR_Vsj*70zx8*@S=Qu6gG}I5f zd6duaeQnM;10|>FoxVLXwxzU7zec@Lt@M|&7%VYi0`Jb!iJslh_&=Sw>2AtX&$A51 zvf!iyJyF%Lv%e`NRARXe+b%|p{m>jjf$1|1u{*tnUPf{?I11qmHvp6lg}eAU1*R^)P0)W{sdZks`aX0T z^u}BR{LGg60bH+nbKYfqksP?@!A01s&D8WJM(wxghc>8&@SoMUB@8UC8E83`1G924 zh9wQEOY4o7BJbCl)MqSRN3UyI_gmz>7d>a(hkqmyrG){%Q))XdXQ?`VV@OvzP?;0;tLPc75;nSc7(Ws&M+ zG!>Y_I#p4vGKFC#k)X9AfE@I=?!5zLCQtz2ZItA{aL@yhGo2v+6Mse17Tkuo2IVj{ zAz;@!oo6dT(TE%r01j1ov*Fyy}{FEuu>bQWwN#ohFAb;=+C-15$*$G@(?MEv&j-R$ z@y%$^?{p;|kUl_u0R8}Ac);9}#y0+l;DeqO+-fDnl-7WQ8oDC{`;Ed~Wl6yOecAR<1-; zW+oM_bRaFDU{g|3GP1H>QCFpz94FVBv_(8MY09syC7=;@?g2nJ;6)+@Urqn}QA#O7 zW571OeQV#C7aGYiFbH`-9iw{-rA0qvW_Dej?W7_Ui8VnC3Z|a zcz^ik8zlJl`a;-rb#s&Rp;H*i5?;-AAMFCD($)2Kl3K}!G?D4WygHpT_y4?}QgJ;t zyvtExrA~f6v`6^aI4#^!Xh;1S>9eY2M}5STy)l$o0VyddNhztj-ZU|;?qtxSSH>CYcvp#Ns?GYS*FSLfd000}% zJ)rV5uMz)$c-x68#{l~CsX$TDO_;=Al|n3&vJIb%2SnFC2OI?G{~o39@sMIagtfOh z4NgkCsAlY_V<+)^eNtb+SxB3oDk{IEA{wk>?(6Tb#XL-hG!3Jcm(x%51{P`-CqJ?768Q&4KS}2MP6T`2S60~0^sA;Wt}A2#)m1+tOMSwm@7PxU{@Do$2_KJ+ zT-VDB1Z;=VSn#zJ_}<5Gzgz~0B4_$=`^+4Gk`B=FL+tr}ZXM}Y5a=&x^vJDOPH_Qu zji(cj2*o5=iQ>pT+~aJygQ>by>{;fgV8A;xdx+sm98Zu}6CQb9`@f=Mc-tufpVtlS z=%E8oQO=Me5NFa!O43rBTnw7=n?7hFR5b`u#;$OqW=b-R9~#Z37!YX#c`t50q*Hf!tA+#d6nE3}>Xo&@ls8vfWk-{Fccc#yFE8(P z3w?b}zU+j8Bhb$LbQIzq(xQ4I-gp}A!fqYPqgU?`Y;b0u_?hJtV_`ByVocSXwgK)I3`P?dO>fqs<`nBGr)y3P0@|K!ru*k+sdXd(r9asw|J zQEUCBQZz%(^|Ts+tOY+o@|-f)|5%k)-0S;G1!13%EtN!!>bluhZ(gs1-*hb!<6?u{ ze`)KDs-9#b?HOkR4Do7a%>AC$d|APE{N2|4x4h`{qzrTrOWNv%xbba&qMURp>;eC5R?=+zGD>p&kWVZjC?qZF)ZRL@+Bu(VwEqv z(M&#i6#_zU|2y!9U7808%QJw`+w}bV_XdcSQEm*)sB&7O`TyGG?*T}&g%i^U3%UK- zX@Mcpqs478m^n=_DQ@;Ig+qJgsGp%fA@GzX&s4*U^r$u3!vOYt?yKKLH1VX`)KfLF z*m?{>&ipZ3#!&ZopkMu?ZgE8n$fUz)!?s7ffk!b9c%Gkgc#^5-f@iKds~}s7YEU&x zb30!$ZdU{M>Dk%kSPW2l3I{Bn^ofp{q@9sLYR%5GyvTtB+D1;2VQxcYLl`r4%Ev^X ziwqnXW6EHd+gm);p>Xuhgwg3nj+f(v!!f9;iEDEG<#7Ir6ORwn-&vc{QptjN)4v5{ zjW$c`2s9;{LaTlWbAGTDEOSuz zCg$rw>{A5!XD1rK$p#V|)dw7V_nxgm+Ws~zIA5RVO8PlJKhN?^V}`mtMcqa_;eiC% z!(<1!7=7meCsA#1A{nH>jJ3LD^T-CRl&ZLb=STvou|KH5lOT1)x!SUx`WeV2|*=pab(=Cj`i8%(r0fD~4un)tai!jD;86A$Tce1p#JXYTq z!FOn+1{LGNGfo{JGfB%)MF&*=<`-W_@Xj)_G2tSf+obeCH?IEo*Gm_JY*pAAH|_JV zVK*YBGI=1B3oFtKAG!zx&iuc<182YTH|urZU5ybwu?be&?!Wf?JSLP?wj!W%}oOFcUQYN34%}Zd9vmL`y9m-8X zseO9-=^&FsI}G=qQ1HD3sJuLOyxBqk4@v$uAtB!BE@v?6+wu8B4R)KmaZ6SlpjkxbDvKm%J}bHW!;p3~CB>WLo3QXL&T$ z^k4&Bm<&B8OIHSt3r!;ya&jBKRla@jjr_;DKv8G-{TWm24BG~6rUnLBUw;${2lZ$X z>c&lVZ2h}lCu?i#+U}74xkgAXJq^tXmE5i zTWlF$fB!aI2w2d!*!l(04RIZdT=`8L{AHrPS;)ps5K0}y-^t3#%E8##fPjga>Tys@ z;MzRm`_&Sp36=8H`{&ZrK1va4a|KKpD%t~^*xTh(%%DAwufOa>Hx6EN8fjxU+m3uF zg;U3%`@|7-MPg{B^k=B{$|y~~qxUTzWSc|0DsYlbRu?AG{G6Z&Xr~bO-gopJ^(5gWst6th$eSO_cJV&nC?E4fZ_i1Zs8#~R!MSL4xAEfp`KvpV zLrNJcO7#cBBqSsUMn5!nm=sv``tx2>er30<=S7`;)R_*KFc10?5T(TUzU4&`-$ZEW zx08Q)WWUei@5NplU$(cm(|&zZ?YmYEWFZZ6RR>!0F6V@@?kl2ZGrenTtbwOR41d6O z+jEvNQyh5%r~zppC-$3LRdLfia;_9036QT&5i$!k?N<(M=Z&?!o0~87eADa3ivQvN zPu?5eX=+;@0M!q)0P0xD(pj?2Qv~SG81ketBe>d^^|G`lf z*#M3Tuk^$q{9#CG-Qjw=Igy$AMR^hJ)t0`8u#}XTZR_%ZWv4Hs>7JY4wXUXYLFSfC zN5U{<{ZTdwzQ}QW%$mAI^xHpw#)XLJ6ha1VKekiLd(n~GeGns~NEP)tX1zPJxF@?m z=DiO=B9Rfd4gU$=mg+xd$u?Wg27=;el&ih#D4U{1PM7}ldH;GiT!0$)p>@DJD-V(K z6rI@QrBArt;d&~llQ}9NArWiXaWzFFIi`-Ts^1b&vFF(q=YB^~8IUJNWcQWzN?M+9Myv@GMbYP>Vn_-yjLFb@A00qsAtqs9C zW@Z`S4PF&_Kn7+y?mVR(^0xWd#-Amr*QyJcNVR&5{ggjoFm|K+4=K-B_;}Y}X$#rkai6s5*Xa6XLA*E1*2J>jsWPbia({R2da>voS|1KHQmnZx zI|P|>727_)hXGVK=Fm82Oc#53G*NFkTHjwm5<5m!rOVcrnNMGI8`6WCeI#)rB0u4- z`*p<)*WA}$9nBiXq*FL-#BEEu6uMmt=X!H<)PHnV8?=~iu0c#NeifbaHDaBSQcrSG zMv7TvBTy}1VoSl`BW(JhpWYAm9X?(6Lm&i&z}F`_Mv5X_kE|V;C@g@iF0zCObQAr9 z3&c@qJgvLX2cSw@>JqVBFXs0?!i6NZeu<8T#_wQm*U4*I4SH{f_-Pv(K-H-Ufw4xZ zU}T_2cA%TY;o|3Sws4xdpj^FvBM3u9wKL5{eQ}%&K5GSpl0)1>T-tPtyMP*9Et9@| za=yQ~Aj5ae-(V@t?W_C2m?y*@eUCYZ4;G6nnkb-B;WOs3W%H7aOp*IZUKyPh3)5TzGatZr5Y7=ZaY#k4Z1yR z&-$opQ@TL#%noy$sY;-8qDc8@sy2|U1cn?GDrTY6tuAFz>NA@1Tuj&0)XYhB`1mmy z0X(cJ&i#hU`b*RlvUe4yiJ}CJCEyB1Fj_uck^4@L9d*Z3*lPLaq>Jj+2jo_MmQxa* zk`@U|prNV^n(yNWjmm>Y8Z@P^zez1#lvMQlzI`bc{sK`&`iHw;k|b0_-}TvPmV3Nm z+X~s2qdppbZjs)wC?DMtDdMlAAuq78Jk2P^Bu;Seju`GIEa(|=yJugDY*<*v{%?Y# zt=xk~*qschH@+{rbhN!PFd~y<9fP_um*_8+UEV^6rURDk6A zK}yR9uPKO1-YMVIRpK21arf^0_5CylWvcLpNFY5WiB(Y}5<@kS5}!JpagGGyySiY3 zu{5xw&K;ojK3wMwqEb$vKg$!=qo$$yl+!i}4`Wo8}je}N?Av+51$f+})aaTi2dT?H1UN@XKs zZp=AugXjqxVyuSM34x1;qVOc|UIL#%3U|gci(Rily?u0A-uV_fQO>R>`{aXFJ>>(e z1;tEC$I->tZ9r%rTe=@gehm^Fghv!d!D8bnTpZ9n2&=DqCT!h5&94nB+czd+DD z7BH$kQY+3-w=Aht$vI?%J)vME$sPVOE#(CkfSuQmyA|Z=cYE!QK(ErzA$9baR^m}S%6*yteOTW|DP8cBdSKdAi@c8aXI?D{l@ap+u#vV=L8h_ zSkuo>7^qMc>ceL)>c#4H#HbDhIz%^IB;rLEl#a=Gl^t9NUu?5QZnf^Ckm;L|4%TwL zhNVy30kT7x-UsdeRQvvC-FZxf=2|p0BFLB<%+#zZjryr0&$AiNR8_ronLj`Xesh_3 zFZzJNI4N{+al-sxi);WWtsqiKXuGlwXxx9fe8ZC(%y4VU%+Jut^#mT(cX)3{qf`^i zzmvz^*A)3S)o%CFjrqI4kJyajSSx$e1nb|P%jQ9n5j9_E)85NhO?j-v3fk%keMN|2 z27}3A(!YT$UH`rSD!&poi7PtA{j7<{LJ1{>dR8uQb&~jh7U8JvJV{omYJU<7Ciu4F%mg{9_i@A?1mTs#7BKn|JuqinL| z?|D@w(zt!?gTZmd#4IkOI|@aN^lDGPWxP%}+Wz<Fekeh-@Mg5$O{$JGa!N_uo3nf2DpjMwp+&Sg)@>6~BP#57q;k zvcfz6ttXD#t>IrJYW{bq`p_2_7bG~S#(ntR{ zBC^}{M%OgDjUoIeXN4m|`H{NldM;CXRMgak)QnIu-v(!{rD&xGX=AM5l8rG#oQoc{6 zXM?3fHS_QahK;RjyAz80;1w`vAJ*Zr$Pzoww~U95ZHBU8S9ZByhFqxttNpZ>NaDAB{Qp=w%do1pt_^Pl2^9fBT9lTM?v72TG*Xg+ z64IbFN(<7R(jg7fA>AP&EhV9dgoM;L_IbZ^ar~p#X6?1soO8tU+yhMvw(gSw-PUWp zj^z8P{fka<&l!eJ)Y%VSK)j!66rDPTwy7U;8teMA-qP+&5hCc)WC?0*BM&) zq2ddrAKh1}{mh>@G&C=g1bZFXM19UrmMvRw?geDfC!@+Dn7t-w=e0L=ixntn*|S+0 z+Da4m1mtF1IorI2;otR`jsLzGx?n%($u$kRrW;6?G3t1^b!b$^B*!XMOTK6?E5F8SXs z0~WLkyDAmg0zP!|CE=+(E{m<8_rq3>uuA{!CiE*kioi0sIF8%!Jk{Pk(Uuxjf&TP$_Jc9b>E1%%`VzF1qDxaOJ-+ELKfpK z5Pqh(SnghTlTIqIub3W8s!^c-z_Ly-BAFUajc(ec$$WZlP81}r`P~A{c3jC?J(zvH zeK9zX2+yFCp{3s@;2egX?_Qa5XXLpOFHuF2(*?cPLF!T$B=G7bQxO=nR4l4}oA>CF za!KQPq<)W+n0RqQGtR=r=4*qz(#DWM!c<%Fy_SJZn;6q}X+-!`;L&J1-oFC>%LvUG zsW(@h4pHdc9+X=zOoEVX?)k>=TD1!_t!$~AUNFb+PgyWKWv#B+MXr8t_ecK(9THA) z@$z9CVwwF+(M|1~=)@cE+tAw+TMy~sa92P5-6t7E6Y^kF^b2)_#RT*gUwmxnQQNk0 zl2?z;{FA(qcIBll>={2kN%z^`x1Ly;`KDBa!!k+fSqAqqUf)-s=l0li%3?=(+rs?M`_J4IgpRv~ov|jU5`F@KD zF-&kkR4p~ua9KiW4vqiGkv9r6xy6H3thTc?IJ$<8GM~FR9+DN(Siio}zRI%LVTV+U zy#;**{VcXT#NS^7Qb-1w1EseR3a+z7T~btj`P$WOLvUyS~e`1o!&mZAwE@a{;dt4pb8cDhoRg9LUdQuqZ1_ajJG)!GYm%I%u-^ zG!;itn0C1w?XZTRwm{*BI|CynhgS+G9}cHya`~fJnQzyl^Lqpb4EU(sJFbUJ1+uwT zvNG_?KkYD=HI&l7F1SLfSMgcoa7_BsZtL0k4zp49^OoCENS(sZ@$N~28C^fL0xwOW z-b#~f-?OW%Dl*)`j`fYP-7~{5-uvw4Hh-J(;&r(W*J!AsK$LKP;iCM0L}xznKlf{# zYsj1y%_%B9YT5P1JM}U?`xDMBa4$#xvYLWLhG$Tc&oo1Y^Q%(4ax7=iE^Ngpa|7a{ zOYL|uY`1WWG=3-OXv0a+&~-{%wOCmdpqCs}KQn4nSR2Bs#{mN3Kzj!ADPie3)H@`y-$&~ckz{+KYe|@O0aD>2EydK=>R)*Z`v8lu zn&`8Y2;Bs?1+tOTV}uuY=+D1zmy|F13_hx#?-0D&D?cA7Z?@MKs#JlEsgm_)VA=uT zaX$B3>>JeCE$w~#=>QVUv;*Vd*O`A`T5Va5t`<7sov)B&JJ^;oO((M+ZQIhBDMu*I zC$vmCDf|Kv#Pwlh2RQu*R60@x^QpS}mMxBcKP7rc7s;I+C_XLohe?-&6tipp@E zJoLFY87eFXBkrxvU9Jnh&PMK76&waog93Hvx&_y1pq7Xa-NnK#RrgIfF$;sQ*zGR| z%r=|;8udlKlcYb~=BgP`MFa0hC{oIRO1&Ub5E?(Nhk5L%7UPR=SnYT#rCQ99(++;3*Xn^*7clCGs)r30=Elx%S2|I=WB))9V?G-z{mruxM5&+isQQA$>o;{|rc z45*~veM(uwdJ_yg71!&ZRi?2OF>Fw(iT))LJ4hZq=~3dmxFs1G9QxHiv?5K9Ek;ij z&yE~A2 zs;ne}tR(u$*LW?Dz4yFRQ&T^~dVe%DG(<``KG2J1T~V+dIjQjYaK!#w1saH4a!AwS z1Qx&5y@S2gL*#dq!e73KQvGVH!73NS;Oq_gAELXSYB$B|X_t47k<1q~=Mhd`-naKJ{{*Yti9HeS zGZNHDmeEsnxiUVJ1B;wB)@&`2a|uWk26iGiLAP;B{BkcUHO4M% zOo7g#nztjjvVwImDmi+|n}+lsQO~<~85=F-3*L?Mn@lmD>ntXMfN~N>`M9 zJ43Z9pep?YhoH*hgW{G-^o5zC6Iqpo6mw%irVlyvt_$0Y@~)w)ja0-pkD~YTq_R!fYDy6oKNbKFO~L&Q+`irb#|0J7UI`fDi9+pMD>P z8uIrrw^`;71@a8(swSg?OR5vs$-Y@I$>OUmH-7Y8#o3q6B`iTZ!C<(Lmo$x^nVxPZ z|CX9IA|)b=CLzR@h83&P-}<3J^=*^0*=Y`8;hPdI-?Pr`CmG2$wB2-!!pJIbJ6)rp z$=&Cn8b6_Xu8S~CRxJ>(%ehxKut^qkI%RS()uG3FG#J5|DvxQM#yQ5P@lLx$+qcea zpK?-x13{ikI#pS`1iB3nKR94F#*LQmGZ@^WsS1VdMNR}2WU+bDw>Sjj-S3%H6EDLx z`znYwhQWpGRI)RGRi*vvFeCgZ;WNL z)yFVJ(c6z(k42T$)c7gQ!_ukW+sVdf$fo%f+luB$<9mLN{z4NIvFWN)&VJE2-C{4- zbmr19Mo6dm?1IE`Pl5LpT+kv-&rZRv4Yen*iqjh zoHNx=xIZo3W}{qXHH0e{AhZz0MC*ACe*S<429u=Z~_&UCH|GnK6+-BgL;2{o$(-)(s)P{soA;qMU^4;>IDEF!c%43@Zq=H&iQ~1 z_b1|n8?DjC;)Dc}GEE|11C<~~MNTf4VlHUUeh~|31Nx#}JM96&E+SM8>hYm&WOH@iYJAyt zd!VoR^+@UWCf|n=1uL-aG9jSJ-9XgBPCnTs!FWearWYaMaHvUNmHP@A#S?#)yL|@6 zai4#ana`i8ICY8>BCDe7A6-wE=XvaBvthAxnZo2Q5j7nXWN7-D&b zZGCZ++;w0j1}Xq<1EEYWoj8lvf}lSqU)r!$ea_(c6y3oJNt*}ovlKadeu1O&eU<;U zB8ze^#H@%VjZ5o+7New`#>yTndergp<%^c)p}6%I+itE{DG&Ph^@dU3mH40|Ls=eT4ICK&+ z&tsT~ZfpRN?p}>fAoFUKwZ#GZlW05r#CeU&M|a}31>&jqVA+2<``tuQ7n<34t`sg) zuE@JER##1+M4b}v^x|vY35gvy=#n)O#{EO27OfQ9nKCp(0&Nr>W$0q%>AYebjY#%9 zyn6FhQa|cPt3IK3dDM?8dlo4(99$9Fk-5Zf%J$chB4o8mBvqNDExX^i>Fy zN%u7Nk!+XZqk{P|4HYEKLa-_wxqb=()&)w^^}Qny*O41T)1He4J%BQTY0h=+RUaE| z@h*~r>m6sBGoWL>)uj)vJC&P6-~R8{g5P#oi#guSXqw~^lThO2+DyQwujrC_e3Rac zj{Fgyl<_8@dw+Scbk&kAHuJC{N&BQTM>j7;)mHOOw>fsH(?_-Qs4sXe%*#= zIW+#<@-+7B=yRC~HP1_2KA1WY_lx~0uC)%>ei*OVN@V^-0k6Hd)V@Kh$g1|sGbQ>i z>>bI1Qc2oYr5pm2yDpwr7sqFWqOnG@^NhVUg=wA^A-kfU??XFQa{hb7Hbqa$XsDt- z0F5Vp=l67X4vPZFLwLdXdg}kY_Bk-|KwqT9Nz)&~pJ88oqZkXxM;VhY7mu%I*+$Kt z0LSJ%|#$JXuxw*&XtRu1WFtV#^$3 zYP@WL5^q_}Bbt;EDdCWyzV5i|eh*sPP*TsA-~BS5_pCi)@X@exH)??{s;)j5sgFYy zxNUAZQ(|?S5dgiAg3q=c`~=3){T7WAXjv=@V2nQB00oKNe5<#x@ljRcGCjK|j>za| zO*PTCKw@H8cv1U=_f9C=@J(+L(Sgp{m*BZT3Ct=~&biA-2#Lm<(>CuG9Q4Oab`NNgoye?2q! za<7{N#gfdhn{#xbZj7`T5#DXqVoNN!jf;Ewyvlh*5G&Ehjf}1B+zEk_>4VbZJQWUK z@O#9wy``~0r}EZVq?uxst2KrU5mg$1%sf}rDsMi4Bv3W}InCVAOlbTc9_})(vw7#y zWoQZ`I_E6A&fivnL`g+{b?+1VFyQ=vKG5H<03bk=F6di>Gb5kvH$O;UARy1qrWOWr zWXqk4mWfTF7&1!AnzOSrEMPqmAmm8RyGy%0QIfH;DoL%P8*XjMQ= zVN<7?J1+-cr|iY^sDVGaB~yPOE#r?T`1u>@lA}dfG~7s-zJl>U+Na)T&L17?93z27 z87W!psrke89!L^En+Ul++;~#+Z#6cAvT|}DdtAzmgbf9-F+S74px~=-!ZVPWjvflc z6H5~J++VvtQ+MHpV8{CI%hltN-LcPQN3lU@{O3eY@KBYrebhxh{ z4qspeh$^hbUFHNQ>t#^sjUI3a3T|O}_G3?+xm^pfPT+bP9Mm(p@R1zO-c%@7{oBk&&1F4Kl2gf2Jc|9 zy1pzhPYkquVl(J;$BGcYoj8({i5M}~&t z42_Ob-2Y^cte<;6qLU>5<|thSDUII9jCk$jbO(aEfmN5?vH><}Y(*1Ged38N9>ZyE zD~9(#sN>+`icu+;WPk21UKfx-L)N4B@e*g+bs6%ZjBJiYQ<^oAXOf_qL{$^cU#;7I z%>R~TFTp6!8_h#_TWCw>ZG3{Y5T|tYjR;N=)V{`S7i)wmkwy1GDDo1Z9ANSsf2}=q z3wpS-0hao@WlsuN(O-o@Y2NvgW1-?n+1Cn-;!ut?ic$l#$u%r-AZvXN#^X;{8@h%_ zQ}C@MkG^2>cT?ge7*85!HZ2XJn^aZfJ~fJM8S3&sFDl4*F8}1kjf!0HbU8iJ3Bbc$ zzR|Odx(yWv!MQr&IcIq(HL^>=jnjXOl)ZcR5m|z@fwyL?8DAF`IYsra{DDmeY#(cU zyi@G0Uk?Acrw-&yij2{)X3b@M;LwXe_mgLK%7kE6KS01`6CWkPfdATWQ6Cx^&Kj{5 z92mzRB#meOdMUAv1GVH4xK?=LT=lpexgb zP4i1iISMLjHO2n**CkX*qP%F(3E`!kOnU#r zlZMEw6v4uXONKes+9%!7v~uJljA9(=R20=jHG?{^I}wjP!kAR(NOrQa+B<`TA+I)b z`xgU4ld^i}F!LHJX zU%vM<3LS&uEmz*8+k;Fkr3@V|F+9@m8B<}W6Yx3r_{^8SXQJh~rJ;5`8n;0rxONMC zQODg-tUGc$Hb6a;FMAxG&qMsE9O!AtliZZINmrzd~HqP2M6uQLi-mL*H3L+L&Ysxid& z0r2jeXW8@}>c&eKZ^_i^=TaHyZ^k?w0c4_;m8@sP$d6)j=gyCu=5u@^qc1eZL+yy@ zQy~goPIH%el?*S5__D;&wk;Kh8;P9_!%)vb z^LtWuRIx4lw%-I(g3K>3RU2`W?f^i@JY;)o2d=M~lh=_2v(JUDM<3?&YG_;K6LD94 zK}EtQZ)G@U^!$31sT)I!u$iS}A_k}x?mEG)r~!oLL1wp$oN-<>QB!rb_YEx8@368( z{C+%ToHUc(j{qJpO1pUJGovo|X8LB4MFPcO^dkuworN^q@3x%3*)7wP^A7#z+x92= zSI#aWJOL0IGj~IHZ}?F%5Wx&bqWL8S6_I_fuN&?q}c0Cf@QWI>%ZHg44Zd;rkL$%y-##Y zBvFWC9ICT(uyJ2{E2$P8u_^#)gtu#bbjHLmxz_Lny1eL&jdqRPRx?#I`23T(L~JW|63#ErcKwD9~4%OP|A z3GBylnwrS?s;M`E_IdPKea@xTPs1#eGcqvOrFgmrLjS67`xptvm&wxM3F(w->P%0M z#sY_Q_r!0=IM!mnCLdig1FdgPrZC1JCB{f7a`L-AW>O-4$e2(9tQw+P{k4?&2pw39 z*=Cb1)e)S{e>!iz?V zq;3by1NpgbD(R1PLM?<|ZTtt5caJzSa}>nCucrmV~(@aIiG;=!x>Z8`#dT!u*M zDvIht#n>LwRL-Mc#jZm%Zb^2LUkk#?Nn!^B7I6HCNZ^`ms+JFwKi((O6YfGg4c4{_LKexoZ+5)Vz( zi`k68Ie{QY{%XBjV{)RDh$djmtFI{CLb^#nEJTTuP}#<8Q@DYqWJ0G%VuNJLQqtHi z?Ld0x_uvEAMmc&$_Cy@i>*_-?rDpO|)#hZ{JZ2fFk@*(iI?4YH^xR$CSBgHn#?mWzgP0#?HaFt@}0R3CzNQ`PO z>;cpKo9!8?spw^o^JqyLsI-ktxjKF(kdMziBQ@8JJ<8V{AAk4a?#G`Qqk^MvaYEwi zv5E%Pglx)^DliC5*DDP*a0$MeGm|A9t` zw&;$-wGhr8KC~no_qMGu%|%N%4U;&35EcxKIyf-7yU_FpJWeFuO%B^6mH&nbVYGB*x^r`pnClZ>2tG-De0h$=kp7 zWzpJ{p}z4KT0|w$hT-nzSF}xD*BRL05@McRm;Bh>IJM#OV7Cg)%mj+T=A1tVLbj_o zo>wn`5mYfCv@h=<%jq0#tU@ZEX)4@aoLZTqfSFHCPW8Y3DJJ5$u4&h0lSu&@>RRbD zsmO^e7yQNt4<#-hgec{O^&(~(!C_6~5Uud%>rhc*Ha>;mV`XK6Y z?UP4i!}>`Aa|j`!?Y06svR+5y`#pXR1LnkQZyC}C-A#354rDh)3MtWDMy{FWW_IJF zo&>IT&>CEFp@wc=Fpf}g(d{X>2JgRie0~N9uhs?c0%^7ATYj0>JleJzwf49g|B`F* zCv4-p)=1)MzZnToEROD%jkB<*C2QzR!DgU|T|{fy4Hwn9yIk(<$PlVb~d-5#&8&?66Ab&zpI@t{f%jih!$Q%acLTtluKe{Zp!cAhdVs@5s2ic zjdrK2*d1e*M`LAX3i$m#tp z-kA>WgfyjyH3e&i*vI*Av#U%4**}-^casL%&CPy)Ib1mzQ5l&&enj3ca46%2uPijh zp|0@ANy~n%Xa4m=lLM-_a?hw3Wq2S)g$!AZ3YJMk+$J^6fFh^U33pD564SVeFkAf$6Gnpo!S__l>cDE5zEfo#i`dcq$!7m6oy zHhCT~Oto62oo=`tC*p|G_rt7~^0b2`zqnBSHzOfdTq8wR3?SkJd8z5euFm}~>~t)e zB>7i@XITULXsqA#0?ocFKR(~*(=_IKQlrf8uT5$2BTcQgX;*oZSK-ICo}^t%>c;c_ z7&*N}t8}Er93OxMq%ZR27qHW#LY|J;Cq!JBXA%BXZ3rHQ)H} zGnf=GH5z~F7{+V&cta5~F@*bxTD~v=figw_Rq2APUfZX&# zVi5XgIWP8Ga8=kf<8_I^oeJX(%Q9H7?*I`2XUtAiEjrPsk@ z3{B-?H9A(CYxCnrq*=Z4J&tKaeiBTwwJKf@v4x_OT91#9DXOuMo2c-g!ClY38?q|J5No5ra)-whSEzi%=m{%r;f1@;ru6-7>(9Pw(L+%7MB%_IhAraI zzx;d_Y{USF7q!&q3U3{=q=1YELC`Sh5dpM^b;f+#7mdiJNIeA{6oiXtdSCb9}*Vl0&%vN z(rTchP_#l%g{>1I+E&iF_6Wf7FQJS$&SdFFMMt)OhttzLsVZxtVBnsNH=?uK5^f`fvd&efTyipXAvP|lXibUrimyNl<5*1FNOs0T<7l$*}j zu|@OP&>?(2st}3A4xs$Yz6+gIUIrBU8noxyN|mVIS&Xg(+^ z1ak%`LUgL%wq7OIA-dCa9rh!Pn{TMT+Kt6~wp_=t3KxP%zzBEwZ>}CF2 zM5BcVg6R&Rmw2tV*%K44a~P1pOHGYkw#G`!(Np1b@d^-1SM_X5N%A+Uen=%YDPKN{ zq$vJ{zOUCK=pNR+k_h%qA!F?cO*%-Ay*{Y)?_l$ULpACrb$*H|)YO5S)7tS_Sp?6s zSf;D$9QC@FsIRle(rlu!HqQZb`sm%IP+#nfPAB6Uc*;*Dvzc+^W6aWEqyp{E?@^9T z!9f>R;yLY-skrCt0nCia%^xG!Ug_Shsj{OmsJEZWkW+OdG4;eJP=2%S*G!sx;thS4 z%aq5ab}TuQ(KZ*PWG-pX9eK1Fu8khVz{V0hyWnd&1}TU+D@jx@)UD$&y{43v_MU6W?eFWo20$B-Oe0w%bAyZ3ZC%{!JjJ zZ2b`Slx~?0-hDx*T$Vd@M`?8C`duPE%NQAR_mBn!1*MD-()Stq zAUQb*bkO6fl@l%RS%0+-@lP`&n{s3pKmoyT4_2LHBnt&Bql}Tt;unXLYBf#eosjDW zIcH!ITQSBxoUHjCh3zOl{Ltkl!MNDJjKOu7-%%HYH5&KxA%rJpPia{BwE_h$(xHv= z^-9@D79eOStrS;*#A;PP zL!uQz#gPvq-bAEA;`y3sK2019QtKXMMT@?m?^KkqWY2T=0l8S6-3!rXt=`Zh(!0@p zdp!GHx_4GLkSLG zI*xp(xl)oq!X3E*7IGzW62q7NToWd892pxn@P53GJU7_TX7F{V#EM)!{|j{iBv%P; zqvYYsJ|^-mr+jO}Y1eVZ=j0R1*B&$cSVy8hh@3formru=;jqB2@te@NtG?h;D%ik?|0}78nA?J>3~WV!GE(UgG@1`*?v^GU+k=zrTb*6% zH)3DkxZYA%SRbbJ)NN5KXV8p^f|(RS7x^c|Vdb%(?{``S08^>8!$hpWs}#6U$;pCV z`)mClL!!}OL8EHg6_)yNK-3Nb9UOS^?(n}^% zYWk3dWNF#ZyP)Yne^COU#n7RPbDeyKWE~C(V5Kc3T02&$ZKO8^#sDt79BbgS!FA_M zPE-iPslL<#o*aOzcEw#b)&HwpY9>z2T$z3!8j{dSPNsRe?v#UF%5~CDN=n+ko@ny% zIU%XJzbA-?k&+1nI)rN}r7;hI?4C2+to&YEkNNd2YIzE&8Hu$qY;8qyXekK`3!Bd! zUAi5cvTX9k^mF&Pq21JYXEz7!W?V~`m6C1AEUfmm5mx9LuL2ljKPr0mYu3iQ3crVa zT%FHpsiI!c2ZggW_KoUd7A~2e@_PpNbG%i-zwuT|I<74=PGAExHeEw73!)9eJlpG{ zytNDpL7a7|biq>DV^1B%hk3NRXv5lJ=7~cs%BpYaNc=M*!9pys@A8gmt?3OD6j`jN zrzd5gWbqk6vHTSWq2{zJjJ<*$t&}B0kxmKFN51&<=uLk!_oIr1lvXgt0&x-(F`}t_ z+&=Cw?OHpC*@uUIK}AW~g!@Z{0D>&KW)cFfb z?L7%b56Hi`@8@bG;of(3b@}u<(!|)1z(G^h|DFzLNar5O92sU#+re442DoO_!^pB# zaNUySEg>6ybL3y;P&gse0&*pLy;1rh4>+3Q8oCj+VB`cl|C~)=)y{(bvrgMfvzo#?-E2DCl0Q=!knoPmsP&Tj|LyX0#6L* z6xNHcrIKQq4)O^_fvm+bkJSuKf{qBZ@K%5>{ju%x)qnPrZ>pBu$+zIiH#Ip;!Lj?s zO-eO^rL`AzEnrk5|HagJobD6;agaIDx;v&{>g4%s?pK}T*=wMdJoTp}H)|&uBY#vnhh^HNS0`ZDW)enLd zI&j};CKGI)fUXw)reeWpiW8E!42aQc?nZEmQ|Dv<^9KI~bIXWUq%g)~ZL5J4*4`hF z$;s#HVCV(#^RWP$#>wdqeQsz4^3S{p>!yLxAy+Wxz^Uo1O55dLKT4#%E|vY~08G`0 zR?b@})&QzyAg*r-G_z-DfUbf0HQ7{}5AvH$zBX+?*mkV9otb!lB`;>|5*s(JWMh>> znuJ~ApXDy=_K9HiI|LO$U~kPgcPTo>S@|?}Ll73AIz#NAdU%k=D_%#r6RE(4 zhjN(%hz6b=NPX75#I6o{@B23Yl+TAIDgwMTKQcXkBqu+w74iUm6?_A83kwYBwnLWS zvu)Q{2?~d|Qj$ftX_Ho-A>;M&3nL+F1)Fnudwtu*PLQ{j1IVvp-fL~KHeJ6YeRwf7HU`nT0BR`4Zp$&u z#W9`CS4m1s8=3~ozT5GE8MKyH8-KTgl|*!yw5bXpwScn+P(jILG?IFo&%BZpIN=k6 zcU;=GszIWXu1e8uy0;9$i?G`-)YaMTaIOS?0>WnoHOYgjHl&{S*cok`lF%sNPaqpW zX(Y~!jf=lr(O6$A;W`Oc(Whs-`5=LD#mR^SzBY7%0gN*$ekB5NSOzO`I9^>-6iMJm z%|tZN;|S}N=^Xd0I>Ok(Pangf$ppSufQYj{KyqUud<17iAMpCh{drjS@1W#U~dZFt;#PDUubr2rhPRCAMG$F^+QebsO(*KUF zzJb37k{5_vU?12}t+7k(cWDGLFyPJ<0q>R6) z$M@^Y@bEB1k7tIwW$1#Q5&Xa{fIkx~A?N8hXij!&IA?@g;-%Z&i{A*FW|sOxuXoO^ z;(&^M(L1IBcG$~zKxHCQDIs*Ue1kJYL{Ins&W)KWnb&NOQ?}etncd`r*~gYND49Q; zGbgv2=D=|nmK|-rD*x(EB0=^NPbhs%HfdWU=8v)Yc|%?LZldv8Iv~j2XC@9m zgBJ$|qGn=+*b|fel!;Ha)NdW`IecHJA@XwMBA6wjfGnN@PB-?833jrLyVO?p>*t;7V}#$2S{bN8%?L% zyZeILN{I`;baU+JhVQ08B+Sb~u!dCf+{~ho)S=OjBNwD{&hO-ahLA zfd^m5hbNSU&7Tga&Rl8kOvY>9`%p}~Id3{wZ8%3;gDDtbeBKI<7L+h%psOKY-aDmv zJA^*MPM3k~v5_nv+0%}MHBTyl8{S84KaEGGn@^zK<|WoP>X=5Zz-FB?<>v`(m10^N_IXm^-3aIWa|6Yc4k7EyL%W#vxZD z@nIO8d1_On^(t%O*pvzMg@UgRHzC?Mr7N4FA>Z7x>Yupv$dp{ROPc^Uv<740-%=H0 z|CFxDf(upUr7a)Dzebw`mfLY9@7&7K%^Teo#M0m3e~EH331(`GnHy!mAFrDwS&8|% zFWds4Je2u6(ZvOaQyVRApT?Y-H;pY(zrpZm_1Hq2Y$ncT2xg4IDHE?~xx2U8+oYq7 z=_1$<7}Ws~J-Q1;#@2%h{VjF0W=(&HP3`&=m!)g+Iig?e_x>JpU++hwCSnJV&lEKi z%A_G{6F3;snLAY-A-M!!?pF~Jx{W=LA97t!d~r5|y_XT6?)20}dW1kw=;&qK@ z*6K>D=R%fP;=_Q5_m&s52EF$`$fru>O3jjRZl*emX_o1<0mrKH;~_Jx3vWN79W=W~ z+&#tZ$@Gabt8I!Y(Ff6?8n^u{zSK^;uB-*5Qey zn|)85Qe^Rr%u9&Ew(^uX{+IHioD-&gJ(g8h;9L=7W^X$HYI>~Flm~v02hxD!og5F} z`2BYZb#|YtSid~y1$M4k)xt%qmWyaV%Dx1HpnWK;)5^wF2=5`R#jo=dbas6Vnd|#a z>rk-79G&bOiJI_)>)?UjRktmo<|pekgSrwdTelk>ti?Ow9KY&?#(oa4Pak35eBb{! z(G3@YP=Bj{l+==a^RT-QMo_bR_A7CSh|E_Q<*g(f!`UpJWFR6dQtlN2(aik&ej}cf z@D!3ts%h7&IdnXcm!%6AEm|&?Psqq3SAT(=(cwUZU6MaE#80DtZ0PO5+q@(o%xAJ= zV;hT0F}#DV7Mi%q%>_`7{j@*8vRCHdt<=zZYh&I7)35LPW`r#wU7kZ|F3c8L;BDp^ zzih&G-(`{GFY1Da@pt*X3l2G|-Vy2jc{o>TE+<{n!ptUX8BVQW!Ko@lgheZN8mH-k{GUvMt z!HTfkl(w!ZB*2QVOH@-ON5tqXlPH5+{L^@->1!$cFzYR8s2%V8YW!UfBY3r%&fEk+ zTz|mtd%!;Vk(7U>;ZeOd^`-c!-7^ESURLryf9HqpY)A zMJW+|&R6f7!>l`Y#@Uxpsg+}W&S0hXn=T+advZ7&hfw8Ag>7{3@s-B095&X#V}?c? z!aic!=WN(c%%q<8A1zT~Le5u3GN>w^vu&iFI1I`#;j7EttJV_S%QqPh$Pg8*KX;9$ zy?M=lSvC684Tm%YY|4UoQ!n8yRO)K#!kGh$ncK)b-xPkuO^hP(EjMYS;$QOOzWlv= z`LW18IzoBmI?FqIeXO3i79r~`lpSyd^~yJjq}rOAZkudhhFEt>y66*&Z=DUATsoPA z5oCuu)5heq+k0lR9aNpS#@>^2;d!8@8)LQ^J6&B5;eRP&!jAtFF& z&i|tU){o`#lKRn_CQ~RgL~yEq#mhQPZ#tY%q7WHyp)#w&SoO@%2;=PT>|4IgBNkH0 znX4Zid-}CEs@YOM_&)(Mqn4!vo=0LR6t7o-P8VvimZi)&K@anA{8lE6~ur6Bnh1rS8dV0T-1 znBL?6wUDc$h7zH`T19)!M!SntOwxQA94F?3RgFTOCbCcuJwNwK<~-8wA;lU2e}XTM z`Gd|ZNyGRalSD2cclSERh4SN6J$~$>+qxV?K|T<=B)HMaIr%0Fdy@kdCoxk0;(k=z z@7Lq*0`;SBEwAfMdTN@v?kQz58$@_S*lRGqU|oy%kTGxj6^HRXR|MVu|RV4oX7v_+RtB0M$z7u!Hf5Iu)p`^$h+s& z>m0Y`P%%oy>*L=NIRuHyIyU&mSO2EXq5P$Y`=(U?{d7z=5f`)Tlcev%P=z51WGo)& za#VQG>cDs>G=uYm@KvM*U>w*55Ut1{KF4&-aU6tooRvjt*vM<7%r!dlK{NwN3+Y8V zizF=tu0x|dzHs=S?4OZ5L_r81xh3b3O6Lt#L$AGV=t1}kUR%E~qfyedXk+UMsvF$0 zvvA5D{U^{RxUsa!%Y?Zp8B=5~?q~B#J_I4p6F)fwm9hPJ|rB{{=&Qb~#vL)XTvptSO)5}99QO?NgU7A2_1*i*}K~yv` z>upgxqk$uPPKAorg3e20U9J^sp0-{7E$;HZ?=bH)ieMw|XjI?!q-=J=b00xv z>%R1n=#>TpeyHCkzMAG6;UgURSt)PAB2UBftQtNk8X$xR&RDl8J@m_T=A_)9bB*%T z@QGRrrI%tmDri40C}A#8iWG!hB-NpHM!aBq8RSUWiM|O0P=4LC>XS^AF#qAI5sQ24 zmh}?%zeg`_fv^_Z6%pawWmyJbcm;n}mQKm(9%q8(3^?*Oe~Mjfsb%^CSa?B5T>R=t zF^>y`mF1a(%V}5C=D(gcow?_YRnws((hkbezioIfZrtlVWrzMqGwLOn1nAeX8d~#x z3B^OI&~7siz?P#(KqaHr*ttu&(|4l?qY|mb3PFa;ws=%mZ$nRo@X;96!JjdqaS;X_ zee6F)uPgi3Q!87@DUv8g8 z;9p*a3G!>rz-zpZ@QQZ!Vc$5PLwScA#pbGRioz|mxP+QzYs}Bdxn}^Z{JCQwy6n@89^9^N^3}Z~`Uql5@ry}u?*dhh zrR#qzu`xdE3sth-#1lW~fQ&kx`+ht{)ySX>A5BVYcpDZb=AUidwkJO^B(g{bP)922 zqG$>DzHyGA1(!@xJ{RlK|H+kORe5zp`tp8lN zC<*Mh#w`XQs`C{VVdracwRZ|D?%5Sztaz?1)sz9;@SB-(VU+M^#AS%{WiLQcr|Ztd zN_k$Tpe_az?VQc;FCt~X;ipqHkeg7e9K}nQ9)7vDD%00!Y!u0@A8(~kYz&g|RUo1X zB6x;#`YI(hu<`RkqsDMK2yjK04vl!nmS9uF{n@oSAKPu-W%~elbIWO_RW2b9n0~;n zGmx9gjEj{X%z4B%a{6=58&8K^RE10LLBh>0T+ohH5w?SK5Cz3JwR9zDEmpfG+Q%H9 zIA9}DvkOh2=HIU6pMMOeQj9PX#{a@bHC*fiBCWf$Uub8eCmO$Ef>VB>LXS-H?i|Cj zEhw%%3P$hS{RQgKmtcfB@lT}D(ufQ2b3-*G0(V-mSVD~%lm8-&^9fx8u>q}%32((q z>3wC*h=>!W1gMMsUsY!T6=fT>>p>6+K@g>s4kd&kqy_03lrE(i8kH7F=@RLZ?(UFA z=@5_*5D_J$MLD@xiVDJ4~bNw`|!zw-w3o z9CEyDBNsAC+&5C1+Gcbv&dciul*WC`1U@3~t6tENA+WG7TED1}ben0WL_o5R!5spt zT1hL7O*CZm*M`u_gDv054Q4Z}N|o!_nb)GA1&*0<0F7zNK-jYLY3@gPF@#6JItB=z7y$Y_24NCbdM53hvw_@kabl1{+B2JO(9I1 zXb$r+b{Vg!7fr;u806`X&!B}?09e=yBN(So16hfJhj%jDyaIS!q3-C#f&sh;XI##7 zxpp<|`xSE9f3SoRV+fC#IM;D@1!6~-Ho~mm32`VhUw^+|T!Nu+;np)Trr^zmK+L7d zo~QK$tAj}Jn=cRQiY`l$mlAbzr-+V2@ zwBi;F!{e@X6e^QZzad{st!k%Y_PZy z>In-f&tH*Y`UwvrnduxJ5RxUBp+Dh~%GBS)@$FsP*2Rsd9sNPx7ABtgoVD9E4Va5p}(Z1jRFN zSI1g>F1*F|Cp1+0xjT<0!dC#ItkQpk>SAtigN_C%!CZ6S<)O*fBZNEom>X&KU58A&?Ph z>?+$ENV-y4qmm42XT)1H@4(9J%(GBYj zjZzH%ma^O?>&k-}P00E+vWonF4<0;t)4bi*%vNpW$~ao5e5Gd^#;0@^(`&IGDDxsz z9|s*zk}OAvZ~c7%IT!|yemL(V0dmj;GeGR9PG*`WR>Jt0LK-Nh3m_^a}u!QvwVzB)fIlhcns6WxrEa4V!it`r=8%34{%!k+MQRYvtmvR+wgJ5rKC$AAKZ{!f_&mX>NiFE zk*stW-egs^RYf)SO@hll!dAyD`05*ATmyX~y!P{r_U{vqE-4Cw2!~)gVwAjZL_Z2g z+GqP^uPCOBD_EF^DoX46=ga3x`RdBjS@EK*jwSoH5HW@@FSa+tM>H14mh?oYy|%SS z_~HxnXR!VvVTVA#*!eEj@Uc;d|N8-wJ4!5)e6jE(dYv4YI6A7ki+#8uEuBdrNny-J zmXlfrR;oWRglLcNd$ed__b)da1?8>opq>pZ)SP^{=1l^Hzdva@&g{Ht%~e*xq;K&Z zYZ*c$(=jGLuwGEt5|{N%-t}G)Ub*P5E^U8)_(0G4ud@iYl!3kLW#1>xa^k$d-c1;0 z2Y>}jI2^*y`xWj)j*Y1YdH80Uz(@hAf>E3z3sF%n{a5I(J1ocR08sOEYyRB66PsI< z?ZxmD{czSx*~{^X_<(|Zr$B1r`2(A-V>nIJi#KK-OXDG5<)0yn@b3K00i5xZyA9T^ zu3xV8M8c}~)I5Khda@BR3hY1ehT5^DuMA_b$R{iSM9+qJEU3FdD>hSL=zIwis{QF> zdV3@srMcil`JAVRa$vc-LR1@lL)CpOL;=>df9oYXZHKKDYq#08BulQVEd9Fux-!X9 zl9@7%S?YR3n6XSB1K#eQ0as!j4jE3>Zz!9~(|O$htbw8CI;FqJmi5S9+kIhS;nu4S zIg3^AyBC^oKxpFAL3!fyx|?dNPz+-m3}O`we2Cv%iM7zeL?p_F17@>UOI&IM-c{r6JXqh}?rr|Q&(*Rj%PqwouTH(9H6rSD2Pz)u=rQ3H zOsMxCGP=h*jqH)?gE8}}A<7d0v&}C#@^23|V+M)NCVu0VvO*jpC$!R_5oJN*9OQB7 z_{TM3;svN$ae%wRxZ}H}S5#(z?)5%r)o`bA2PTBrP8ZqHVEd`^a_QrQUrSFPF_J4I z(FGB4X*S32fkfT?y(H688ttQ|I0-n!BY+U1F}Wg~eHFB9VY(MPOhW=UTUvg0<2zjs zB{ZXUfPX;-aWRn%FHO~IJqL3`g?_@mL?rEluj4)5q?UnA5t(}e*nSU&ov-CUDgB94 z<2NB5Ygu^?TIupnjt_PR*>4@M0VMiAFOY30)nvD~8?9;5pTmkZkeABjCoCFOt#Mbh z>~XP*1CkY6;>EAV`D!%b_x*A=6X<-1f9M;&mo1p6^vWax_T>AD%T1C-&-^36V!>m( zl>(qrD%T?-lTcG^n*50?bZyA4_8cH<$kjE}cE#hZXmA&> zZ-;kB4KAO$+}E@xdz<6MXf@g9bH3u!0}z&X1BJ|~%c}RCMfwYIH5*%-Y@-^&T>@vm z7wHaruv)0I-d&K!SPEf6pU&xNU5(O|b(#r#Cco&`cKtVi<^AAr`*hP%q7#C)sVEaY zv33GUGdTm50}q6_C=ZW=c40rBWjwRAafDZb)49t(`>=2|$-23E`)}|AFf0ooJ6v5n z#vDp&4dGZ@fihVPJ&6pnJWP5NZ{#L2z5B#fd=~KN4yCclD8+^5RA#flWZf9u)|CCW zIj6j6|2g9dg9hmkl$t|<5p)xRS{2)mtC{KsqLGVt(k6?>KHA)Xfnx9q2+la$wCq_* zEH;zw`ssNKqNKD7Bq!gnQcN;%wlDoDNZn&|I5EAV^NNzD_d}Z7_ZboiG9118^dqAL zfqnvW5d-Nt)l6?9BNx)PJ?}hw|1(HcGCdjftF(WiGzRri0a-RNucBK@VZuqS(ewlR zQ`Hkp)%?#vLpu#*C45R>oFfXk$gX&Y@x*EzUdc;S19B&58cespx2gnr)4c909}G%* zpR(fa13gj)?U%9rLL7>?2uM*5v4lp~BjkgQet>Bt%xr#x8v#@u_+DaZMyD$Cve|0U zVFMcx;@!dC(9o>#nA>;(6fOQZvI>J!2%zpY3n!-W9?UgAM?ae;cz7qdaGDKaVd`yO=||>$<-PJy)J(P zLF{|5>H*O~sOs_ORUy4kcZ}rE4h6xw^RR_-FrsFRRT`|P2CV7aX3{&h;_Oo}WJNlaJ#7l|{|Z;sjMzc~_On!C;-bIuX#jgt??|MLOFxgOD< z&y=mnj-l#*fSP&c5R!iC&PVg`qUWLn##1xw-3ZGnNVwraavwfUL*##q@@2RZeWA$K zf#DX3{aejZ;r27B&-o^g13Bi|K9Zctf%JblOR%aQtd=iSf)j~DVxdm=~W)8u-6)##xZzwVyMhUkjnYP@a5ONV3&C2_vITKxy#A9 z1ptDjj^KbRnh3%mG6^Z#Sz-?S0=TQZ(IMz5r3xe48M>@ z4%QQh6n0);^F-(vy0buMpfFA;-wTukkn6rSc8)|AZ}W?NwTLzxy7>?`Pz`&5!H z%CqUeQZx2#c%_*8@#yQ46$28p)C#;H#A#?fncJ2VqxJdfGDiri2+(tkg04$-Mcr60 z;bM1i3!md>h`lhd;AvsMKE;4JjNYR4R1Eod9ZYDj@o3Tr%jBz)#P9S6W` z`xEKbf{poP5Et<(8QoFam{65Lnxu1UTuput#Q1SQ`S+` z3uuz)@D(v0sHnzg#r=vKmXp2Y=z*S%I?9Hd>*rV7if*4{?u%|Wf>HOQ5P(l86E8%J z3LD!o_|PgcG*Pu3-3Ff;BA-83e0*&yTEDnGP9Qqkb&wo`;+lGKpXS!6yLbOGjE?|@ z0A$MBiWaj67v~*U#Q*U7HcVZ#^$NRvoOZb}HlYY6WimKUxStE@f5PqQF0pbNix5M+ zewFzTafa}fxbmm<8iaZURA!Ka-$4kGeAxtCIS{&ZYb@SmBx?sF|Dhc`MAGEg<82fa z%Xfd^r>uQGSX;9OtcV)dpZN>5wq)${@O%j+FR zkT86EGN14()#v^B9JvwRfV6<9=2VgLMe#mZd6)`c0#~EbIXlm1A`mamV5M@=wyEF*>1$ZW|U`qOnprx{} zo=Q?LD`Y%b6TPgL^2Oge(0DbuT$3H+P-QnO2kvpC#F`qiZ5#c&{VTk(!w`ZCgaf-Eay0Ra9 z9pfT2T=gfDXwc;|;pYE!$+BgpKGvl_x*XoS2scvJ*vCTWWp?WojE5UA5ze#(wYHGa zrb+j0QLD@`Yd0P@Ew7Tzn4tvCbfUYP=g*!&uQ`XoQKB!QNTX35O2EK_mb#)B1R|(i ze7QRxCZa7P&N3c&9C&Je6A}=pPvbdwo9dM4C~#$rS3xsDL!zR!+`@2!V=o; z+z<9S3ZCjRtpcymXCmoh7PosbUZ}U!Q@Mi;{Oum{oAK58XKLhx@?4gWy!~O$ZT<~l ze|lHZ1-G2Zl?6!q`OVn8q$E45|1wC`PkmnbJ=eU0v1h}`8R3*BWI5q<+kAHS<>NuZ zO||nLxvc~ySrZd+5<3LD^oyxFRAxGxGc}g&E$!uU(lYF23}DUn(Y|5M^(Oh%pw}FU zp9w+o^241rC^$G?c|2_S2@Ax!Fczl~;iqd9H79>x;YPSDhKm6AciU?i0WXs=i?P$+ zk+XF{8dyu|E5_)p*|HSLE>kj|Yb#P=1ZMyo6al#?7}d(L5v`^(jMw~fH|!i+R1Q2E zN*F|ATxc;(LgSBJYsj9qD?bjwjdyP~=GF~{>VD2EV0!0-IH!Ji*DvdeSTZUbN>8A; z0;LIm@vuHVe+~t#)~}t)BebH7yyJ^yXd?>CF@=vO^>!bi2@qQ0bGDI5NgprT@KS86 z0OM=&`tvMl0B2N#@H0r8nMcDN>1?HQI=p5$dI3>f{SB){WsWzW}QhvuDr1 zlzHy{=po4NdyiH%tvSkApD6ZQ=H;<#%<)$ilV8)AnOg!*bwWeSWejQt<0NOmF!uLb z$nsKktwiao(wl&A!W1NmG>h4OqAANBdR;`LpHJ(BDHznF-fz{<${|k4R!;Rbgwuvo zQn6t7xHR{!yUC9kBSGco&%Ih4H_J?0FkV#>SvF}S1THwg+b_H`?7Esz^RkJ$A8o!q z(|?eE(`Ck{Rz6_ha&o4ltadcv%56-uxx8gp2}qDV4b7@&B7!etbMIZT3oEXM0@lN3 z6Uqh;DL@MYEQ)hbJ>OugPVXT+|GYioRp29+EISv1M-;*gHzQb_<-by`Y9O4|5;w0Z|y^hcNm}hPqbk7*LZ4ai&1vp7u$Ips)Og5i2g$BI$ zdiIPMD*ksA#?9sJn#2Brn=)O0h5AHoajf zCHK{_@oKLFLV%0C8D7>0cKASt1$ z>xvsal9fUdvZYpMATD7xlxXT~7{qRgGwFW!eR8e~&!TUU#7!4WiWdxCy~mTyHI`Qx z6)gf)uMJ$i{Mqml|EoS=i-H-}!$alCi0isZXCUIim`gsoT(N+V(sz$OM$gty2&HOQQakXP*HSQzYn`zlyuO;IvV{pNFsBrlVxWmU zPOeqKi&00VhZi64_JEle=Br2(=#lgaxyKFI_|!eZ29iB!?d zHM>V5mw20tEi#sY9%V@6>)@~$OYRI~1yMVJ^HW19V!x!R6Q zF&;Y@LiG-Gzi==WgWi$}-lpWHZvrzWeonu8jhu_Sax}cw%8h4V){C z2g~c%SQo;`qV_Hk7vfvRt^=wnj6f5~v!&@@W2XA5Q>5vMErD(rRdg?IBOUO%+%XFe zj~)kEC*DuessmnsTFn&FH~(4m`W2U+?yg(xL@su?7+|uhA4&!Wj1VaK1}3G#R6zdb zCH7X2C=Yf?oydU{i;mj-UO=o=Lf!Wid@t_5%1h2o&D<-Br0BO~!4LV(an{e(ZE6%Y zg?5Zk-EVL40!!id0F3#QP0@-66%;7G5Ur2V-%l()*Jh@SH3-H7DdNBDPdHX!;sE33 zbp_;wL^gsmMIW4fgjXoOgQw)4CLLK3J3sQjld9Gm9)$ ztE8&IbgA8{hzBl+0{Ip?JgW(c^mVc8K7>3td z>?_3lq><&sJE{44C7kvS!(Put=jwvBm~i9qors#eB)zz{F@=?3&|rcy3pnu^;r|#!a3Ln1#Wf|1Q1Lw&0oa@*4Bn{{ty%0u{D)lw5try5I8aOEOg3g0 z8^>s(MoA0G#d{r)f`Y*qdS?Hfj4nt_e-uHa0doF%RU{Yy%LSCq_Kv{eL@V-|Xk&R7@O1FYOT$ zKRxzrGogBJF#n=0YNbM#6J+UkC(Rbz(sFe!&iGeO1u4xA!3|KJ%}g5$?8$jCn+DdO z#E2@=hudSQS@RguNnFsA&Dee6E*T4LE)R!i`YJK;C0zxxahQMAv=2-REwN}W&K&G6 zj@5*88T4o15{wB@F~D?iC!u{SaW3?0Wu&V;WmCXWB6KTmaKla*WN}DCV_tB^t#seR zbjvT_5`5MLw!WTsNZenGq)la7&pSTV;h1_13A!*u^02K=m~*I;qKY(a6vnxK7q~=r z)jiYn8Wxtg^kWKfY7EPZQc8moxEm6|slR}c8=s=_CxbQ5l0#Ml*%Jq$2H6%Th3=w= z+6&w_hKa0GGl06C&6rKk*pwU)-1G}6y=m>s+$5Fd3!f3<{2!3qW2(w8fHspy_Ie;x z(vpJE#$(#6scpi37JzXO-eG2FOziA1+7<6eL2BbCYaVkr#%xnJGz)%H+t#I2urtL_ z(b5XUFx}%$S71KXrJXU6)(*FBgK}NJ@P!W}zJ&{EH0s@pS^I`FQs0X#C&e$MM7}{( zoS*&xW-T5Y(AZFfhM`l! z7=%*rr8Ij>o^|eV?_wX=jo|1o+dDkd5JH3eF~UwD90;s&!Y`}NsQ7twi9_Y;m6I{c zH&>!p3?}Qvj9b3ACbQiMRZ!Ea5EScptr6=j5G>MXi22gJ7@mi%e4S~R%a-o^M#p~Y zp6$m%>#jsSX0icdAfdm7jVDONnePZxb#doLf=P8YKPcXge{x-ZwfsR<&}uFB{tpx) z2imCx;}AvM12YzaDHpF@h(aMVgk=q$j81SKfoBW`dNvA#ve1|$ozjd*j{s$;3zJ!G z;qHvl9iY;;o9zK_%?tS=KlP%x42Gm#yTG+6ZG8Fkq}5GTc2lh)bro7O$xM%jE+pVG z@wZbFf;=qCH~ES1J&vCNjt^NW5!FAtHT3+;M^XXQMjhs#UtlV9&FZwXvq# z{pQt@E^;vUg9FO^(+?3mL70yxrp4&&|7Pvbbdp0PVBeET-KNfaUC=?`Y00FgdbSrc zgPPK-v5WCm=-d*KuH0yl40_olpa0Fi=^*)AHHF4w-CIwRL^^8~OB;aR2IKX;Q5?I# zYNTFgxc>rNDS?Zxx-sUxqapS-6;XTc?#pwK0=CmR!4#9PNfW@D_iF_B@!B(y-^O~D zZ_nEp^1FG#TTP$g(1MYA=Ll9krnE@Rl0Wcl)HsD zSZ>6ZREHTOJOiE1qakHOaX0cYaZ;D5R4{Ui9&FAy1@IhXV4Wh6SNI3|ak?oY$3~$e z!P*RZSQQS{u~Gx=_M-Ltd7QMfZu3!rc%I1$|KWr@zv<`28xus?O>Ksps1iP0_wF^Z zA1KwWsqX#4e?81uxQYsR&n2UPBl@dm1_==#fe)#KG64Fy|4>3-@o@Jf> zWO4t}Uh$aADv9<3i?0Q{0lbrRtogEScwY#Us>K&78N5_IOtMx zn_=lp^D*>Pg}7G;9SoOZIF*pqX{vWzLT7XLVAT^uJmxB1Wa1QsKTi*ppEJ<=-sh0N zC^2TFt8R>{x=$VsSMlFTVXD=tw&eY&BwVYV_uUVd(~FBW~C~r+}*~KX$ctP3}fZyUn8x0)|NNTGNg+;uqF0$9AquRhfREReozoQR*5)~@=DA!`4!$}5F^mO~!J z!G-&uU3VFC9x5ATtha@G-GDAjzj>4b^ZB;C#J|sXQ`-GWqERb9D`NZ24TrAVRg?Ac zU@e5}WXxn~vL6?1;q%jn`1|7T(zj6Fk9tObjatEZfAyctlz5tW`^~xpr6y!N(IQL1 z#uWY9J-dvgVU7c*s5lG1b*k)X$|~aZ22b(r6-F|AIoSzEpTYD5=EmN|9Zyd3TXscE zjHNOS?_na>~ot>zdhy?bELa@h-E3}(`8@0*SCVlcq>-<1*M>6eDAw* zJC0FznZP>t!fz3suiV#gM=Phynx;(p^p@Mo{#|V%-g$W}9_kWO%)9e)WDn|Cr(NmA zuJ7>V4(xJJ!x2?tzP(Z|76Dq)GQ2cU#PN@);zUSvhg3c;ii|dT2Hmn78+68P%SJXQQAxojFwo~&U{(sNxKGMV%%eor&mh&p5Jt*Ooa z%BL8VzoL{-`ug&S9D(WmA~UTe&O>S5kV|1C(Ym~r z2dc-LOt0iO3ky;!x^TtaJCmhOS^gz!5hv|iK~A<|%2~vZ;HfSxox*kWB zbl#PUp0I=<4n&Fb)^v@p$1~OqRcFaJ(h6)EINet@!?RO3@A?^Tb|M8NCdGI4Z!jEa zKt!%PqwYqu%g6jEWz{Q+Ij{YEG+6vbBbOUyT|tRy3Yz|d0bleq%WsAFh43oa*G>zO&k4j6)+U|CB%HFGkZ&mpjzG*dwr=tpSy9X$m1w0{_H<(#${n_b47mP>8t**?iAO z##HE$n5DG3kHUep~W*byi>P1T%pNkAh!_~<8-8;>n=XMjfglolL7A7wI zr_D-ia8YPSCi1*qyWEWJyK~v!$CM+Iv45pw6HTiMiT=Vg`rA+HdB=ij!FaGpPPPs@ z47WEi(%dvr4EdXw7HW;K?I!wr9r9MN-}@ef7tgMEo1b%V*XRWgm*j0En+0Yu?&j{R zc{GPmiHWkNC$?2qoouJPnO;mh*Fm?WcZUoeRZ`XxlJL#P)GNO&enVAK=WY40w%r4f zM8~i4BjiP7-2&kxX;@1l&Rbb4q3Mc5jXGFE^isVHG4RRJ2)AM}H^kB4PS`&mcSMYq z6*N}Xob?-dnd6z}yc(a%iD$?|Fj_s|H`?7$ilgsPmT-dl{v}M>_jf9*ho4P**voE@ z0;cv#9z_wYq<%$aJEOr|B^MZ&!)Ue!jLL(>SAPAX&fTHUF8F7)U=}6b9vXPaDisXn zMB=Vs@xNKTE1vB(87TgINrT((VRqe|7rKx;8$6%Jge79B5+|%!b@bAdch$3+>b1!c zgnUUs_{Ey;+x@-$>MGMm6jd$1Q>R7>OoJjaUNv(JnF!CEdHnE$zA0p2Ur`BYTi} z1Jy9aj=dNkCk8543X`- z&!mavTjnox;)$voi|qJeM8!xK#nKqE5|zgabEhw?5Jclmsuneb=5dE7AZ zlT@3CwBMNvYL~RgD{Y_kcOK^4Dz`~c2~Sj`<*O=fSd)@zcF^NXq;FEQrN7u} zv=xHS&3M6M4*Ws$+X-eiP&d0}QKNY!lNC#^o5h17Fy2s~$26FM;O6U%Z*NrAr6%2- zSFVL&5jfH0FHQ_%Y5kOBX7iflDFgA`Bo7u-Bb$?H6nXt=$(H`mF;-(oc(T^>~mAE&Rn6)T-_WosrZo62x7HP&R^F#l*fj2s0+O!eog$jNAlvflv z9EBZ>I1Ft?OaXGG2@gxviy+s=I4s61$tJrh2!4oK^psIuryOpi^JTM; zr!P|6#7^N{`__7MN*_8ttV(yr8$M~9L6%G6@VCbnDpCnlb^M_h4kuX;@>yRRcwExm@k{UH5#d@NOg$>5EZ30BxOUCD!QG9OB+o z2|;?!T1P93J|9=+p^FtR=Fkum3TwvP_QEC2Bw)X!%~0x5r|76TDeLu6c&#s_qB=P+eiL<8 z?v$1v+5=;jJVHXN%3pb{LtQB+&ot|b3@;Gb&b%~l6k^uw#IF6|>Y286;gg>uyj#H_ zebV1)2ZdlrpaCuR8gFUFCJ9TxinWZogU!IZPXDsm)q4Ar>yf48gd!QG<@ii>N&g;Q zndA|nm__2`l<-9uC~94M(c{a_S~xMIp}D0x^Ih}1Y14W9b{$BRTIJ*2lQmmpklATm z3R1;%5*mkH5u;gf2m5~z9^vZ|Sk1kfmFifTrAhYX6+Btykm|?*b-v(!`t{>y7qk0w_^91y4N+Qa_!mtjmHDoDgxxf^i$4{U1YA; zm$8Owl)l}KXSp7lZ)R15Q`KTsLb&tI3yW}3H%>iYnzU$8gc1}0?Q4jmxPi8ZQLU+k zoc6Jnp)$Nsd>|=n~GJ4nc;*YHR`{VzW1IuKW-@o9A$iMRaDA~HgM@=N{@5BzAzX!4I7k}GMb;2}I;OzE?N2f}m za0+dLoqdQ;d!C=l!Q=b^x)j6m#1GSX60iXZ`?`l>9{dKWxQd1_3~ay}8N)nPo6h4X z=FF6};QL}%wsfLN6@_av6ykGf^fghMRsAc3X0?fy=lQPvcxF1EiIVb9)pyd zrrMjZ$ceZ0Ql2=CqmpsewNl8bJ3P;J{hO{;dDU(#($lAUvy!qha9P9hQ>t0TP@7>b}yf2`HPk|tQXo^Y>}_7+Re z<_p-2kCQH`nndJvQ>EK{xuZ>TiQ!IgvmA<;k*C6r*RmodYu@d@txqWv?rB5ES<*VNPTOp-D;A+?SC?(+f zn7XMs4a`6$IG*k^W)6<|{>-9C}2{r+d2cSB-TB ztkTWhD@46T%eabH!bTJsNxb_Dm@VpW=+ShE6#p)XvC)btSGvsJ+`dT@6aU61XvKYX z|JAB%a}~ucWj`p_FSx~BT$}dEedQfPb|tU2;LUk3U5Yue#BBtfv8c1$)ycl6xcSsD zZS5cr%7sY0h5!;kApkkb#LJ5Y%mid>X1@I-xF@cB+umZUOY=~DE4J*;4DOL*pvm2P z8CIe(XXZ3nLjspQ73hmIbjxe&qh>U^1XQCHuSNPLlFe_UzH5>gT zs4mAk1!`A2$1N$SgWHon9K^YJ4EL=3FS6u+{(hcSmGRzrZR{^}jjxePc|TBm%YAZm zd@a6ce7bK2dDXdjZaOgeq9f<-#}`6fFN9<$gPO;_6VNsNb+6_vj*`8cOZ}->?yGe% zOEk_)?t2G>eh5htV*tP@AMANaJQ5u8wu@n^_`Q(9@5KT^*6uR$PAe zLdKRm?UyfKDqC72yxZG3ZWA@PqxCRWQFiiXFuCB2V3)r!(=3N~{56n}!f;U2{SCH% zg8A-iTf0CnE0k zl1z$$zky{6E40**p!$59l<0c&_S>OXX=!PfIiG|C-O6Q?k)biQN+*rKo6WzYm$*v4 zCd?4Uh)i9Tv&d_@S0q+!IrvpkjH>Is7XC7d*33x=I0%_&!5&0 zli*-!>*#!5bAGYZM+&D0hKbO+2h6*qp)866B!hQK65n%a6!eRnFykx8dh_=Cw#&Ij zzPzUOq+dkqCf4A=mdlg$Y-kn!wQO$$KAaBA)$#D)NkZaNM1+nqP~|3nzm$0 zYx*{5e&X9HaFNgm36=n{==_{Sm*P|J^Ojewkspjnf=w({U2Mdnd0Z4*4SPR+yad3q z)DgM+0~C{w*mGK6s>IkR{jH9ru{_k8ag1TcjsFzf9;`H=T0~eARkC?ndk|IENC0YQ zFS;jBo?x!fZF%YaUSd%t|q-W;Mo4@S7E5TJYYzSZi5WDb6^a5A1fsGtf`Q>}ab(#Jd7>Jpp8)i+P+ zXDj6wJ9bX@MnL_~S52A&qxkW-8hKTbOn80`_zW3s@R+tN3XN#9#~W4JpH#hSr47y@ z-QOst^N2K|1Vk9da0aeNDt3{0|_$pZYP|i z5jXywi3fEuJe``msj1=VW8SMr{aP>N-5{vAY`}GVoX>K&7H;DCa;duBS(5rP~obA0(A|k3Za0TC*GzVMu?0aMvZRiuGQ6Blzr+kOv4u z-;Ruo_}C*U#lBea)0Rxy>^!A*7!C=uyPH>~lLE`qqz%;5rOULT3Y#qYn{%B$o?5ZR zD26}kS0%kiK1xX`#=BZbpl>}+PE2tt*M{y#XRhOr%A7+g4Krhc)^gY<#v4a%BV*4` zKy%;WGWY!NtJa44`uY~I{;47MmDjQ_jj2Z~m!pUomT0V&F2QZ-KZWI)tS&OLeM5_0 zjEb2my78LeaBo$0wWAXnz3kNcmd?kNpW3Thz35b})lkBqVhW}eZx;vZp#LzbRdo_| zl7NFI+;^Y_fTOqKrv^No!x44*`>}|nQ=Xeeg{e$OB9_AP2Vzt)sdzDVrVHXTnZEXx zb&5s5mDhrkk#Ky-+r*21rx*5H3MeZzY)oXjey_OGG9@-Z)z0Un?VK(x_n{xP$%E6<-dcSuArG)N3l;mYf(?y>tJeXBE!H$UT+kU+%s(A zFxj)n14sRIs#Pc%WoTe%_*+(uIXtKZu}Msm^Ur9eMw9Db&BiZ029aIIN12MOcjyBG z5a(~y|K(N!HQ$s5*C&1S*ho2sQY3Bo)1!jDP0WGA4cPy|_)olC&W@0VmtMk6vWUB~ zePh@D1n}P`#yptg{2)SAtC%vo6-nvJtQZ)VUu?QzZBxs6Jz`zlnmJL1r1(OPrH)zA zgL46)9E+rWvrve$P~)!ScHUO~M~Jf(u_xqod*$Ag3-_z^!}ZO`#B~4WWQnbdiwjYQa+&tV@@K2Rv++vH;lTKG{6MaGI;$B>vS8KZAV`NCaG z8D)|alkCzCZ<|?H^)B+@QR;gy|6B*Jga3t#ZWjOeG%hhA<+2KiecsTd9 z;LgVhgUcf@uu%aiY{^ru-Xhmz9cm83Ct(}a!$~yPI*|u{m+Iv|z$l}B*~j{=BRy1# zQuUiZ8>W`ru{XMG(JMs5_l)hpB0h^BxWUHdpuSui?H0@bVMzjw2iLnuh+qs<7SFmBDxs>-;OR6tJ zP02P}AGIkKBUXGwe6RmUdeEbSMU&Z$t^Hs+?<0?8$Ky3%qU74o$^m8`KF74$!(RtO z8#CRc_+T%VA$IdVueynH@I`MW0{=@#?IZtjG}B%*jpw>Ws! z&AND(m+dicHBGX05SeRb{uiqiS--8_kQo#pXqAFG&t3W2J$ zX9o_fmkZ@473E$yoEe(BxJ+XIF+j{ec=gu`0B7eWMVk7Y@k*FGrg!Exm0|Z~PazwX zUDZKjlJ9D6Z5k{AU0f{-?w&m;)_vrHNp7F0AaWM(F(YaYhn|(VKJHA=BN}DCQLJ~o z&{X*9ol5HMqqgTwg$w>PFGFQ#P(kD=&0+AR$HqG^3AuscA0*rv}OFOHr)$bccUalm>)mc|vY zB&uoCq96XLHTsQ}mXl+^fl^)CpFIf#gw_gMmr55c9uaZoKk2!+r`BCh5z}A26kFjS zkoJ1TUFX3FUnkO&70++^&6_tDx8BGdcKXuZI@g;W)ND9aKOGS&I@uo1kf?ZbF6_se zeEa9=@!rqwaEc0M_aDf@J~>KRr8{Q7uV`y)zd{&d{ZXo!5d+k1WTH~uW4(lZ@Sa-+ znM2CgdV5~B;6!RocFq}3LcOzN`3A**}uDww|n8a>{-v3R&6 z)4wTy_u*tQXvT;ckE@Osy$fTxG}Q@D!9a0_Q=tMeSYpMLS^ zjJ>(1^)+kqY1Sug^R&o;vV`E(9hdgc8~f$^uUc&p-kzY}wY)bdqRmO30TB^5(0@BY zcHbw~o77xwHAq_XIxHq|;0dR7hQbZr$%N^A)7h}4ToJBEK}#DkGE$61l@lX;!B`@+ zZ^296aq#dg1A@W|Sh9lWo=ttg`oxhH_v{b5T0Ls-lKHIP8wpO*L`C?Otnyp_^89%K?>vh6m4F*d6thJwQ zH%(!^M;^|~MDsnrGen+chWV3Lw2QMF<4)0pCHtl8_W3o`agVt2*r)T;Rsn!_Vl90PjCBf1Vq7| z*e-*&Mj2#sE2s+37rF~?Nle3Ir7rg~GY2HajYX;3$f+$2eMy5U7n;F{Yj>iYoP1iYO1WnbT`Ol!Ey!XV2 zxUmX4XD|K(V%Su=-Xg?Q@E8KLmpBhQ z`9BfYn{`g&F$mPRlal#bQ}$3HZYo(n#B;E;Kc$NsBk8zvH}B#R8xcOkBNCizYD&Rs zH(X#Kj|>M3>N<2n*ZX}hTf|~5T~``Q1DyQAt^d`UL-T zpdNbh`hy{6fljwN=Ge!uT`|C{&cJbF)hnBhg#ms6%7IDeZMTveNJ5>=^sDzHO0DW{;%u5f8r3V1Aytk>y|s zF`v<2gbmZM&Shb=^5hS^4tval7zhtyHj%N)w`6jW zG@ZPn&HL2UhXmPWvP1rz898Cwa(HW!&D<;GkSGz3AS1~14C2vPv{9^)-gxy~YLCvP))1<^nz_Z(7zEeUU;Q7ig^5}Ng{Hej-OlyiLux?*1-`sHpsUi z#3%ZfRZw{EsvG{r??`+GTaQdd&|I1DZqgUh9$sXR_#6~!Yqy-@` z(o9>efS$HR@aU_tj8U|r3=$rsCqU2#Bq7XaS@ZZO)_IBk=RdY{Iu{=sov^Pli3kLO z$XQm`S=z)N?P!AdpMR__w%6bVO3Vu~CeCOCFOrvs8!5<*j4QhfjoGScF%I11T(mL`EplF8_Z&VE^3Q+QJ?4yWt1; z@9_$2!uxmyMUaC3^8*6>1}5+W(wM&>XKjZ@aBDfC9i6yen7G(+!=E(aHhXT4=6?PH z{p_BTy@{iO|m)pO^2&t1`ub|&szrgrFO<{mK}8u07z|NC{0@Np4H zB+m!6n~d;HGR!yC;Z0~qP3!+&fdl3e7D!5X_yAre#JsFwhJJ=d{P+K527?6nHVNk2 c|L^_qBO*wi%}&;j@ESr<_K{4vl(FCc0WiaAfdBvi literal 0 HcmV?d00001 diff --git a/watchface_binary_osw.png b/screenshots/watchface_binary_osw.png similarity index 100% rename from watchface_binary_osw.png rename to screenshots/watchface_binary_osw.png diff --git a/screenshots/watchface_digital_osw.png b/screenshots/watchface_digital_osw.png new file mode 100644 index 0000000000000000000000000000000000000000..a1697cbe6d06888a72258c3df9b771ff942a498f GIT binary patch literal 52295 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 >cUOJyy!WZP5JSA!*ARjI-(sWp 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 z zmi95OMYYe(*q>Q@G06B`jNe_=-oIO~z582x2+-nr(wI+h4Oonxl6u<3;YW)0FC$Zk z32(XxQ~hM_{42kIgixZj*noQzA5V)mSYy$pAU#o(h{*H7Ab1g2X)l69CbSA@(0I4cqXrYChu?EfA0licaE zqPCpy_a}WSm!+OyBqIRlIl*!pg%ZRUy5!E>2pYbMo?qV+?)Ss%lJ0744`pK?uLdZc zgqqsg`yFIV1B3Ut?{D{$;slv5zxF(jkhulo0XN=5Gwb;%`}e4p)x{vQYAh!z9F(!h zs;}km$4Z4?DUMwv#@}Lutql?3SQMzm@F1{``W=H{qXuK@|E4lJ8kPwQ8T~W(g4o%v zVjX`e#2}NQB0x0^;+zi`ygE*D#TY=40wGptH-Fr~Y695%k|f*bdVOVs5?VJTJOWal zS+V3yjJFDi%i=5hN|+CZ28+yau2@Vfkf6Tt=<(EkY5Wf&d3fAkA|@0iB#6UvwXL7 z#xR72-NsE4r6pmAGE}Mf4V$EhEPrp7_2FnRZqVcp7MMf*yt=qrurr&{%a>7))hC*X zL4yX^5|_V-@1ZY(udeN&gQj;yz?30{Whjq7@N(pS+tJzgXACk;>hAdO-@ggqwtfyi zW*W@ok^Nr27PFbT#)~KO=S=YLHWK#|edXV=nDW=yhfiLhhb6ab30AwF=L{=O<3H~o zmmksSgVeTeWRXCe0FP=Fg#9@~0(L+o zLk@>Qzp8V25|9m?!G7kORhF*-Xk?$vVlU%luj^&q?ado(jQQwT5?<^Fi+|x;jI_a5 z%a$l+eLImcTTB!-)n4Y~0#GsAub=JnLZ#6lfkza9M?^vSg8er=vNyf5zus=G`I7(7}Da~-AVfsfs6GK#ZOL_gf`UY_1}m%{dD9uJ;* zGxSVh1QwT$sfA0BD0ispy>yay?zfJ-@9#kFaD%)cEuyti*g~2hpa-=3fHj+$Z<$NC zOZ;ze+?fOjNp4XC=Ia$xW8-gL{&QZ@F|v#P2)3;8wD2r&Pi#dSCoPW7$%Y?9u5?5q zS%d#T&`jH+-l%yF$r8MIky^}=m)7JeQA}XO<#73_AINNck-?{)w}){k3G(G`#=*_% z_V;3&*3cdOli<;vRSTH2#&y!neTF38yi_X$XF~9_Y65H{^l5M=C>c?EN z;eNq<;_{ilKU&>4Wgvm*%leQ8cZ(F5{JE6d9emt>-yLLSNk%3LBu$74YI6T+Dl0(5 z)Sq-5hVy^xywbmaZ^=ghs&PRB*^{q^A0$GZWu!>jP`~lCoZbrj60@o9123x~4?q9r z&+Tg;h=ewlxV7s8$A`WCk$lxasO|@)R^J*Uhj@W}Kx+`(p{dMQ_tv&O!7d4djk4=qFR=fH;1s zPQ^0#N2%%kPba5DL7`#zJK^qvC%#P+ zWjFW6NlKfAJkU*->;C@VZ<&Rf;x8mO-&>asI?CA%w5C#cp0M>ty>xTo!Ln+c3kqF* zB7m0Cg`*jyF84{m^Krcj+cpdL>~rgPqlx?K?AvV7F!E8Bdci7NLG!ZQuvZh)%Y;Pz zJa|dw^Lji~YFb+FwBDJXUsrA+n7J$UTIuscXOZ_CUJaZm!1U?LV*YLn}uE z3*NH{Y-ic42%5cY^N{S%}W82TxqHsd7%3DcUp9(N{QZBNxKYO>A{e?+A7|~C6aK) zdKC2A8#JKwZmfEo&t+2s)PJffp@l1kCz35p1vIh*&zP`boXdxv1=6haUTt;ZhG~=2 zunM!HZ+d24B)V17MCxjyPyrb>j=?T{zcT_8sPPQ#T*jezmqB1-|{oUSq@d z={r=Mk}9DJ{0t0~l`NLeA{E2<9#}!6$)ZW3L}5zFEEgbEA{Xad&tLJ^+SC(x*yWmL14Y{P1cs#}~u&6P>ByT6Den9t$^wS@gHiB250!tnx^U7g> z=LHM@;;(*Z77X=JgoTrLsuqjU0r>)BuR=*>l-GKEsTzW$Y|{1-p|M z+#3v9t#Tn{wU)^e>5Y7f<~F>rK|JHRp>+P`%7em6oPAjLIV5^Q;-5qJa4Uj7)j7 zx7$ExpFRj?j&Q1>*_t;qE~DHO37LxM*|=z4tHWJMyemIQNiySFMPF^apJD%iO})@* zF$_}xS#@*0F#{9C3+;psEGRhufCjEtBqv+)vvDLmd!Ca1i}ei>&qGXj$X$1;oBx2h z8p)B%(?0#=f>y&EHkT3J<|xCIYuR6CH`3fTHDDQUG0U`d6i^j|r=|t(*z%tdvMHM!7b|R!mh!%TVBg9JH|Kc{Ahx8?dP3WOa_clu4*z zQljT}X>bV@j?AIa6ck|T3$$3qo{koV3{9<+WTc{ZJq%9?D*O@i@bC5cNq?sF6H#xh zSUw*80k4$F@D}h|?B`Ar43-?;`f5G^Fb;J)j}I4z$QIc7*G*}FmQCOiS1Z*KJk`g- z80EI?-S~by%(4C`pUPUJ6jkZ@m{aRI`Pb{kgZ`PBnL$qKh8k{0OBP>Xrgm0Pmwdip7P%m&{(-#DfT4Hg z0`}p2E-+k>{fC_Cxcu9lKh0yfVNkBOYyP=w3*kY@v{5Sph&Epa$EN>;M6a*@rY>=9*ijU+33-ru?3-{av= zkIQ|JbI$8I*=jEEz*+4N^h27@4#$4dl4}UcBKmVlOts{Hy``5Mrz*H|*bXn=Wg5&# zkb0v)dqdk&cx4XeNPp$M!!uMzr;wX72UqNB=DSyqC9r{XZEM#AjFhl9Qb}_ARtWM* z@bnQ6I2zxOShsoOyLbe|JyMw%UK-uEH=4J6D?5RSLp-+jU>c%U@|g9y4Bn7<_0x^L zhouy+indA7O>GUIii(PM2%*%I)*;FpAFe{LEPR*@om-22yBjh_Jqn(b%HV@ikRS3l zuf8e*7IR4)Is~$cnh^IeHyew>Nxm8;z|AjZU0yoB3J>Exa1{Vgd3*uG9W{DqdbW*` z(@~o@4&eAfj+Vqj+sd{(Sa~G;t`iN-9>n^6CAl*nC>@YR?Ifn#A&@(S@bZ${Q}HyH z37jn%p;bAyDQZzQuzoY)Qm3M6y}NVtq=GU%WVE}Z?^fT;XF0@m0I-e31v7vT@pjD5 z-xo1;m9Bd1_spi*N~?0RZ~RA&mNle7Wj3IQ^ZD}i{TIy)Tri0dbxR+sW*i{zib0=k z%c6;sGntpQZqbrD6I~q5u8Uv_PdkyH_?jif$??aVl9UU~lbQCEIvwF1^)JsLHZFBj z=gZ6XL~R^d+cIwQaEh71+3U+OfOEP<$W&_4f=_KP1$(oIh?RRuFuykxK>uw@c#97O z&&kv2FEjvo?F1FqvLALE$cJs(Mxy~0qin}%l*<8Yyq8Ce(vZM9vS|-fdmHe-r z9c^n>nLa)$8~##(QBw`l($j9kEKwx_PY+=pyI=Z)b&+-|3Susa9S057La@Zh$;nCC zyz9g|vv4?F%8frGDuQ@Y67rYNcreF3-?jU*YkbtdK^St#sHjC?)n4ktzeB*JJIcJL zpmsRlXw$O%$*UD0z#w?U(y|-m>VVkYF!BwQy9C}3Bv&hF!G!l;3Nla@ytlppf`ecwiR4E%Lk4+UckWyV#k$n^v6}y~|DN z&@Yqmi&MiMZeI$R(G*VL?G2J(4kT_PW>Oljz4pD}f;ZGD=Q-K@d+=KE|4D=pVlf+b~YB>6q=UF&@NB&98Nz9e|CIi?ra=~RblSsEM%s-owBWSF1wsE7M{s_2l88tK59L)&BI{H%kfEX{cV_gl%Nij zgbV^6z?|BNODpqV<|9uBuic{%YP=sxSeJp6WUy`g--V@xSZd3NbAgjkcg9>xiIo6@ z=RzCN`S}q3TsxQDYHoet)BA>uh-Y=jd{W9R%#>+SQBm+J)35#sRW|&$Z|_#c1yO_a zB{to*VcE^E#Fs(eMESc7X4kr+=+}uF%vq~nvn8RXh#7p@J+AqEKVt zS(CZmC;+OW0n~FT6vPLKY4F^s#UWW^$bgPQBFr)Trbga>0t`E0s>fjjPkgt&&E)~% zKThN&fiE)Uo}~1F6HY)=*I=CWEz*ITseQi|*BAa?*LLUFnrWc_Uw4ehe9QjN%b!cC zO#iEl)`*Ea#W>HsreYHN>|Q;r`Ikb8OAZ@&2m&;fdtcqFW*6DxpwvD7{IYDPDn5dd z0=`AkTYYP@a~_Q(;c#vj)S(cZM(eV_xh|H0k3U?u?z`p=o~&8(Gbn^g?fg~(X=3yU zrqmCW@FxOL z984q^JYi4Zj&sd8Y}&j^(CPjMEnywSqw-yCeH%lbc8bq@^5X*WQ$~TjL;nqr=N(`N z7;$%hkj9gVf0CYRi8GfzXctF z)F8;pKAxyID{-+b4G1fiF1ABL9P{~ZO8?W-;{C4yJgFt$r@Z^xcXTT!J3&@CjS>j9 zOs7wg#at@$bvHVoPjVqj@~W!yVOb@m&trcF$@-?j$7U>25i-s}rvASiL}o*;*Swj- zk!f8=Lzi4hKOD$s2~-%B_1fX?9V@TNk@(l&@U#3x`}D8hbFicCfP68_zw$OkO?R_g z%Ru<1lW4?girz6V%yZUvlF)|(IozD?F*n=Kqi7gXUjZ-scac<=0e^>uC2^Us{(u!v zAsb*6lc-Lbzu|tQT>P1(26d~NUP7jq>+JmG2qav*^a#YU{aH+{b&k4X#YKzY$tsEjO67h)kQ4L^2?WP%h!$;y<0T&r^fD$ zs5HRZ&(8yC+HRNCQKge1mK(;N8AzP3SYPsiSpCk4#nXjXds`V}!x)5ctvc5SAa7hM z1_3=NaB8j&8Z|0;>}B$gVJ&{RLFgTr5BVIgA9^=r>Bg8mECV>S<@O6ELR%t1W0&@$ z#Ek}2I;Ib#OjQ{erKDRsA(2o*Z2FkxMIN)z?7#P2595H%V?HxCxA>R+yXU&!bc2Jw zjSjy$uC>xWIa>65@OH9Bs;imB_`67aS_1>`Qiba;`%yLZs4E%oR^KQmf|#8CbRG!j z@}Mqj@$tRj`jFMC9?s5x|NixoN#hkshi=rnrf;docK`U1o1WetckwfBv3WaaTRT9^ z(O85r$)zp>owPdhr_OV^iU%>a<8m@5uoB4P(Xu&!lc~a{wM^qb@MXwTt%A@sEQjCB z%k}m3M>gLtWsWxgUpQ9JK1U`2(q zb*_`Vp{gW1obbG*XFC9Ig?K#gvlvYk?q>WpD##cOUYz#8i+Ip^>a(-y5yD1DMeSFK zhrjSG{qYC%aEfj?;%sLWZ3-^zV;hDB2baK=5C=kc zHoZp^6IJx4F`5Yb8i&8AM~?+SSs7uDC!|!4;j#-BTE1-SfA&!!U$C<4hA0h<`NQ>Q z%-?1o?=g;9y^4Ax$CHw>Tsg-2+D>F@fw$vTN#AwzjsbNh_!8;gnTEXqY#M&rTv520 zRB%%uo??N~rggpt#GVo^DCpDr)vWe6F*?jbfB~#slK-ZDnJUdTyVpk(f|~*O+X2>t zo*b0s8QFe8sP?K)-B;qbA4E(cJ7H((nH}F41CF-30U&1e6-eh=p7NEc2`mjW5KhQ3s7MH@us3HL$k7KYbeP5=q^gn_S)3&v}Km1)2ozi z;Ya~)#<$Ns`D7HwMHz2p-G}Sk9DLA|;Ro_9PBQ8a+tbkR3{O7)NA+qI{>56IxC2!LxJC7|9Ta$>A1BhAa@{+-&FaKw}j%gzFne}C*D z4jdwin14^od3kj=%@OYez~%8A;qBu2U-O{X+kp zfg6m*b|P7(V-Fj#?NMIMmY{UUcw$QR3Mvy-(k-||RNg202ke0n01a=tBQ0HH@gkpV zGif4^|M}Aw(lLvk$Arz{VBGk4zgRVUeSUk=>FUN7WNLUeV}5o9l$&doN9@`W=lq`8FM=`D(yi7c zRtugJZ)xK?KFsm=%@kj-xEyvJQz!_Ns||NR# z@4(X;c`-O9lu#voyr+uymbvP?bq6xYeztKJlz+Ruj-HmR(s6bVB>Tz>o&c?clt7UnN%+sGqhj!9$}A zT}Xv|n5Vg8iA_PhI_G|9(0hZa(@8;??~7ZJHETo?+&qIeZmxLq z;%=h#wU>vN9+aJtqOhkiKLvxaX(5R6AX7>kM@US@hAe~@Xs#=sl&T&r(uN%0&oex} zf#}Z(REY!RDUhP=|A4UTz0e<>f;R&NXO6sZp}SFFVM|%v&uRxMLW_4Gp{@f+*V{nb z)^x)*fQj@B3|7&S%J95qS(83hQx;|f8R(E%8|2uda_WY(f!__azW8C??N&egx}-!< z_GNg5@H+gnV@*0L0p+h9bUYat$QDBe@^&5xFvRz**r0!94z1x2lmTME-Zl#fW^7|B zt80!|oC%^AUb98?;}@aKgEb`EtTEhYdMfYwNzwl#&2x>r3eQxm9(zWV@k=H|mr~rE zQeT`xakwzXkVS5Y+nd4UPu;pDt-yPXkEuHxgB;$p%70GRwhcM%0Dq~*1^tV1p}wq6 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 Date: Wed, 8 Jun 2022 00:02:26 +0900 Subject: [PATCH 002/116] Screenshot-script : move a path -Creating a directory -Delete remaining files -Set a new file path to a folder for screenshots --- composeScreen.sh | 18 ------------- createScreenshot.sh | 4 +-- screenshotScript/composeScreen.sh | 25 ++++++++++++++++++ .../fetchScreen.sh | 0 .../screenshot-overlay-mask.png | Bin .../screenshot-overlay.png | Bin 6 files changed, 27 insertions(+), 20 deletions(-) delete mode 100755 composeScreen.sh create mode 100755 screenshotScript/composeScreen.sh rename fetchScreen.sh => screenshotScript/fetchScreen.sh (100%) rename screenshot-overlay-mask.png => screenshotScript/screenshot-overlay-mask.png (100%) rename screenshot-overlay.png => screenshotScript/screenshot-overlay.png (100%) diff --git a/composeScreen.sh b/composeScreen.sh deleted file mode 100755 index 0ec598fe9..000000000 --- a/composeScreen.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -if [ -z "$1" ] || [ -z "$2" ]; -then - echo "usage: composeScreen.sh " - exit -fi - -TEMPFILE=temp.png - -convert -composite -gravity center screenshot-overlay.png $1 $TEMPFILE - -convert -composite -gravity center screenshot-overlay.png $TEMPFILE screenshot-overlay-mask.png $2 - -if [ -f $TEMPFILE ]; -then - rm $TEMPFILE -fi diff --git a/createScreenshot.sh b/createScreenshot.sh index 212141144..30fb68bc7 100755 --- a/createScreenshot.sh +++ b/createScreenshot.sh @@ -6,6 +6,6 @@ then exit fi -bash fetchScreen.sh $1 $2.png +bash screenshotScript/fetchScreen.sh $1 $2.png -bash composeScreen.sh $2.png $2_osw.png +bash screenshotScript/composeScreen.sh $2.png $2_osw.png diff --git a/screenshotScript/composeScreen.sh b/screenshotScript/composeScreen.sh new file mode 100755 index 000000000..85d3f73b7 --- /dev/null +++ b/screenshotScript/composeScreen.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +if [ -z "$1" ] || [ -z "$2" ]; +then + echo "usage: composeScreen.sh " + exit +fi + +TEMPFILE=temp.png + +convert -composite -gravity center screenshotScript/screenshot-overlay.png $1 $TEMPFILE +if [ ! -d screenshots/ ]; +then + mkdir screenshots/ +fi +convert -composite -gravity center screenshotScript/screenshot-overlay.png $TEMPFILE screenshotScript/screenshot-overlay-mask.png screenshots/$2 + +if [ -f $TEMPFILE ]; +then + rm $TEMPFILE +fi +if [ -f $1 ]; +then + rm $1 +fi diff --git a/fetchScreen.sh b/screenshotScript/fetchScreen.sh similarity index 100% rename from fetchScreen.sh rename to screenshotScript/fetchScreen.sh diff --git a/screenshot-overlay-mask.png b/screenshotScript/screenshot-overlay-mask.png similarity index 100% rename from screenshot-overlay-mask.png rename to screenshotScript/screenshot-overlay-mask.png diff --git a/screenshot-overlay.png b/screenshotScript/screenshot-overlay.png similarity index 100% rename from screenshot-overlay.png rename to screenshotScript/screenshot-overlay.png From c60b8a158df0c7196e673c5a5260980baf4059ba Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Wed, 8 Jun 2022 00:03:54 +0900 Subject: [PATCH 003/116] Readme : update img path and screenshot usage --- Readme.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index fe7cb509c..8a52a8d63 100644 --- a/Readme.md +++ b/Readme.md @@ -40,8 +40,8 @@ depending on the watch model. ## Creating Screen Shots of your Apps -![analog](./watchface_analog_osw.png) -![analog](./watchface_digital_osw.png) + + * Wifi needs to be able to connect for this to work. * you will need bash and imagemagick for the helper scripts to work @@ -63,6 +63,11 @@ http:///api/screenserver The `fetchScreen.sh` downloads the raw image buffer from the running screen server, and converts the image to png. The `composeScreen.sh` creates the image with a surrounding smartwatch (light edition). +#### Quick-Fast (recommend) +``` +$ ./createScreenshot.sh +``` + ## Troubleshooting ### Arduino_TFT.h: No such file or directory From 0d6a398de8db9d3a5374ed6a1b7277bd854735f9 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Wed, 8 Jun 2022 00:14:04 +0900 Subject: [PATCH 004/116] Readme : add detailed description --- Readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 8a52a8d63..a1237261c 100644 --- a/Readme.md +++ b/Readme.md @@ -65,9 +65,10 @@ The `fetchScreen.sh` downloads the raw image buffer from the running screen serv #### Quick-Fast (recommend) ``` +$ cd open-smartwatch-os/ $ ./createScreenshot.sh ``` - +* You can check the files you captured in the `screenshot/` folder. ## Troubleshooting ### Arduino_TFT.h: No such file or directory From e48e273d87a79f549c1d083fff0ede1e62813d95 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Thu, 9 Jun 2022 08:18:40 +0900 Subject: [PATCH 005/116] OswAppWatchfaceDual : fix data type in progress bar --- include/apps/watchfaces/OswAppWatchfaceDual.h | 2 +- src/apps/watchfaces/OswAppWatchfaceDual.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/apps/watchfaces/OswAppWatchfaceDual.h b/include/apps/watchfaces/OswAppWatchfaceDual.h index a6b9c15f5..a06bd05d0 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDual.h +++ b/include/apps/watchfaces/OswAppWatchfaceDual.h @@ -17,7 +17,7 @@ class OswAppWatchfaceDual : public OswApp { ~OswAppWatchfaceDual() {}; //for dual-time - static void drawProgressBar(OswUI* ui,uint8_t cx, uint8_t cy, uint8_t jump, uint8_t length, uint8_t value,float angle, uint8_t radius, uint16_t color, int* goal=nullptr); + static void drawProgressBar(OswUI* ui,uint8_t cx, uint8_t cy, uint8_t jump, uint8_t length, uint8_t value,float angle, uint8_t radius, uint16_t color, uint8_t* goal=nullptr); void drawAnim(); private: diff --git a/src/apps/watchfaces/OswAppWatchfaceDual.cpp b/src/apps/watchfaces/OswAppWatchfaceDual.cpp index acf03244e..4e7d45496 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDual.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDual.cpp @@ -23,7 +23,7 @@ @param color color @param goal specific goal(option) */ -void OswAppWatchfaceDual::drawProgressBar(OswUI* ui,uint8_t cx, uint8_t cy, uint8_t jump, uint8_t length, uint8_t value,float angle, uint8_t radius, uint16_t color, int* goal) { +void OswAppWatchfaceDual::drawProgressBar(OswUI* ui,uint8_t cx, uint8_t cy, uint8_t jump, uint8_t length, uint8_t value,float angle, uint8_t radius, uint16_t color, uint8_t* goal) { OswHal* hal = OswHal::getInstance(); hal->gfx()->drawThickTick(cx, cy, jump, length, angle, radius, changeColor(color, 0.25)); hal->gfx()->drawThickTick(cx, cy, jump, value, angle, radius, goal == nullptr ? color :*goalgetSuccessColor():color, true); From 8f6d11bd5c79a092a6c8036e15426a81567cd28c Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Thu, 9 Jun 2022 08:32:27 +0900 Subject: [PATCH 006/116] OswAppFitnessStats : fix parameter Mark as success-color when the goal is achieved --- src/apps/tools/OswAppFitnessStats.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/apps/tools/OswAppFitnessStats.cpp b/src/apps/tools/OswAppFitnessStats.cpp index 9ed1446d1..3d3e2026a 100644 --- a/src/apps/tools/OswAppFitnessStats.cpp +++ b/src/apps/tools/OswAppFitnessStats.cpp @@ -28,12 +28,12 @@ void OswAppFitnessStats::showFitnessTracking() { uint8_t commonCoordX = 50; uint8_t intervalY = 30; uint8_t startCoordY = 90; - + uint8_t progressBarWidth = ((DISP_H / 2 - commonCoordX) + (DISP_H / 2) - commonCoordX); for (uint8_t idx = 0; idx < 4; idx++) { uint32_t s = fitnessValue[idx]; - uint16_t thickTickWidth = ((float)(s > fitnessGoal[idx] ? fitnessGoal[idx] : s) / fitnessGoal[idx]) * ((DISP_H / 2 - commonCoordX) + (DISP_H / 2) - commonCoordX); + uint16_t thickTickWidth = ((float)(s > fitnessGoal[idx] ? fitnessGoal[idx] : s) / fitnessGoal[idx])*progressBarWidth; thickTickWidth = thickTickWidth < 2 ? 0 : thickTickWidth; - OswAppWatchfaceDual::drawProgressBar(ui,commonCoordX, startCoordY + idx * intervalY, 0, (DISP_H / 2 - commonCoordX) + (DISP_H / 2) - commonCoordX, thickTickWidth, 90, 10, fitnesColor[idx], &fitnessGoal[idx]); + OswAppWatchfaceDual::drawProgressBar(ui, commonCoordX, startCoordY + idx * intervalY, 0,(DISP_H / 2 - commonCoordX) + (DISP_H / 2) - commonCoordX, thickTickWidth, 90, 10, fitnesColor[idx], &progressBarWidth); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextRightAligned(); From feb78182f111d5137fb48d58e8265f9aa2f1dcd2 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Thu, 9 Jun 2022 09:36:09 +0900 Subject: [PATCH 007/116] Environment : add getStepsOnDayTotal --- include/hal/environment.h | 1 + src/hal/environment.cpp | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/hal/environment.h b/include/hal/environment.h index b428ee3df..c49bc5f7d 100644 --- a/include/hal/environment.h +++ b/include/hal/environment.h @@ -37,6 +37,7 @@ class OswHal::Environment { void setupStepStatistics(); uint32_t getStepsToday(); uint32_t getStepsTotal(); + uint32_t getStepsOnDayTotal(); #ifdef OSW_FEATURE_STATS_STEPS uint32_t getStepsOnDay(uint8_t dayOfWeek); #endif diff --git a/src/hal/environment.cpp b/src/hal/environment.cpp index 5cc6e7992..7169bc9cf 100644 --- a/src/hal/environment.cpp +++ b/src/hal/environment.cpp @@ -185,7 +185,6 @@ uint32_t OswHal::Environment::getStepsOnDay(uint8_t dayOfWeek) { return this->_stepsCache[dayOfWeek]; } #endif - uint32_t OswHal::Environment::getStepsTotal() { #ifdef OSW_FEATURE_STATS_STEPS return this->_stepsSum + this->getStepsToday(); @@ -193,6 +192,23 @@ uint32_t OswHal::Environment::getStepsTotal() { return getStepsToday(); #endif } +uint32_t OswHal::Environment::getStepsOnDayTotal(){ +#ifdef OSW_FEATURE_STATS_STEPS + uint32_t sum = 0; + uint32_t currDoM = 0; // Unused, but required by function signature + uint32_t currDoW = 0; + OswHal::getInstance()->getLocalDate(&currDoM, &currDoW); + for (uint8_t i = 0; i < 7; i++) { + if (i == currDoW) { + sum = sum + this->getStepsToday(); + } + sum = sum + this->_stepsCache[i]; + } + return sum; +#else + return this->getStepsTotal(); +#endif +} #endif #if OSW_PLATFORM_ENVIRONMENT_PRESSURE == 1 From 81177974cd0f5109dcc22ef01d594da8bcfc0bea Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Thu, 9 Jun 2022 09:17:29 +0900 Subject: [PATCH 008/116] OswAppKcalStats : refactoring calculate steps --- src/apps/tools/OswAppKcalStats.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/apps/tools/OswAppKcalStats.cpp b/src/apps/tools/OswAppKcalStats.cpp index 7ace59d1b..cc22784ea 100644 --- a/src/apps/tools/OswAppKcalStats.cpp +++ b/src/apps/tools/OswAppKcalStats.cpp @@ -86,11 +86,11 @@ void OswAppKcalStats::showCurvedChart() { hal->gfx()->print(hal->getLocalWeekday(&wDay)); hal->gfx()->setTextRightAligned(); hal->gfx()->setTextCursor(DISP_W / 2 - 7, 160 + 25); - hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotal()) / 7 )); + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDayTotal()) / 7 )); hal->gfx()->setTextCursor(DISP_W / 2 - 7, 160 + 25 + 10); - hal->gfx()->print(hal->environment->getStepsTotal()/7); // total step counter + hal->gfx()->print(hal->environment->getStepsOnDayTotal()/7); // total step counter hal->gfx()->setTextCursor(DISP_W / 2 - 7, 160 + 25 + 20); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotal())/7); // total step counter + hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDayTotal())/7); // total step counter hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextCursor(DISP_W / 2 + 7, 160 + 25); hal->gfx()->print(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(wDay))+String(" m")); From 0a4eb8b0a16de4ecf927a6d35a14356e96111eab Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Thu, 9 Jun 2022 09:17:53 +0900 Subject: [PATCH 009/116] OswAppStepStats : refactoring calculate steps --- src/apps/tools/OswAppStepStats.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index 435f76a9a..7b122bfb4 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -11,7 +11,6 @@ void OswAppStepStats::drawChart() { OswHal* hal = OswHal::getInstance(); uint8_t chartStickHeight = 55; - uint8_t interval = 20; uint16_t goalValue = OswConfigAllKeys::stepsPerDay.get(); @@ -63,11 +62,11 @@ void OswAppStepStats::showStickChart() { hal->gfx()->setTextRightAligned(); hal->gfx()->setTextCursor(120 - 7, 160 + 25); - hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotal()))); + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDayTotal()))); hal->gfx()->setTextCursor(120 - 7, 160 + 25 + 10); - hal->gfx()->print(hal->environment->getStepsTotal() ); // total step counter + hal->gfx()->print(hal->environment->getStepsOnDayTotal() ); // total step counter hal->gfx()->setTextCursor(120 - 7, 160 + 25 + 20); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotal()) ); // total step counter + hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDayTotal()) ); // total step counter hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextCursor(120 + 7, 160 + 25); hal->gfx()->print(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsToday())+String(" m")); From 67458239aed13970a1c6db52168308a14457c59d Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Thu, 9 Jun 2022 19:48:12 +0900 Subject: [PATCH 010/116] Environment : rename function name --- include/hal/environment.h | 2 +- src/hal/environment.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/hal/environment.h b/include/hal/environment.h index c49bc5f7d..889ccdaa5 100644 --- a/include/hal/environment.h +++ b/include/hal/environment.h @@ -37,7 +37,7 @@ class OswHal::Environment { void setupStepStatistics(); uint32_t getStepsToday(); uint32_t getStepsTotal(); - uint32_t getStepsOnDayTotal(); + uint32_t getStepsTotalWeek(); #ifdef OSW_FEATURE_STATS_STEPS uint32_t getStepsOnDay(uint8_t dayOfWeek); #endif diff --git a/src/hal/environment.cpp b/src/hal/environment.cpp index 7169bc9cf..aaa79e530 100644 --- a/src/hal/environment.cpp +++ b/src/hal/environment.cpp @@ -192,7 +192,7 @@ uint32_t OswHal::Environment::getStepsTotal() { return getStepsToday(); #endif } -uint32_t OswHal::Environment::getStepsOnDayTotal(){ +uint32_t OswHal::Environment::getStepsTotalWeek() { #ifdef OSW_FEATURE_STATS_STEPS uint32_t sum = 0; uint32_t currDoM = 0; // Unused, but required by function signature From 4ed965cafb2ba7fe6d155aa45033fa75ea463f9a Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Thu, 9 Jun 2022 19:49:45 +0900 Subject: [PATCH 011/116] Apps/tools : applied rename function --- src/apps/tools/OswAppKcalStats.cpp | 6 +++--- src/apps/tools/OswAppStepStats.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/apps/tools/OswAppKcalStats.cpp b/src/apps/tools/OswAppKcalStats.cpp index cc22784ea..2e2dcf014 100644 --- a/src/apps/tools/OswAppKcalStats.cpp +++ b/src/apps/tools/OswAppKcalStats.cpp @@ -86,11 +86,11 @@ void OswAppKcalStats::showCurvedChart() { hal->gfx()->print(hal->getLocalWeekday(&wDay)); hal->gfx()->setTextRightAligned(); hal->gfx()->setTextCursor(DISP_W / 2 - 7, 160 + 25); - hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDayTotal()) / 7 )); + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()) / 7 )); hal->gfx()->setTextCursor(DISP_W / 2 - 7, 160 + 25 + 10); - hal->gfx()->print(hal->environment->getStepsOnDayTotal()/7); // total step counter + hal->gfx()->print(hal->environment->getStepsTotalWeek()/7); // total step counter hal->gfx()->setTextCursor(DISP_W / 2 - 7, 160 + 25 + 20); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDayTotal())/7); // total step counter + hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek())/7); // total step counter hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextCursor(DISP_W / 2 + 7, 160 + 25); hal->gfx()->print(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(wDay))+String(" m")); diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index 7b122bfb4..4cbf42c3d 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -62,11 +62,11 @@ void OswAppStepStats::showStickChart() { hal->gfx()->setTextRightAligned(); hal->gfx()->setTextCursor(120 - 7, 160 + 25); - hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDayTotal()))); + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()))); hal->gfx()->setTextCursor(120 - 7, 160 + 25 + 10); - hal->gfx()->print(hal->environment->getStepsOnDayTotal() ); // total step counter + hal->gfx()->print(hal->environment->getStepsTotalWeek() ); // total step counter hal->gfx()->setTextCursor(120 - 7, 160 + 25 + 20); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDayTotal()) ); // total step counter + hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek()) ); // total step counter hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextCursor(120 + 7, 160 + 25); hal->gfx()->print(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsToday())+String(" m")); From efb39d4f90b2ae8da1434b74691236b39a3cae84 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 9 Jun 2022 10:59:37 +0000 Subject: [PATCH 012/116] Applied formatting --- src/hal/environment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hal/environment.cpp b/src/hal/environment.cpp index aaa79e530..3ccaa07a6 100644 --- a/src/hal/environment.cpp +++ b/src/hal/environment.cpp @@ -202,7 +202,7 @@ uint32_t OswHal::Environment::getStepsTotalWeek() { if (i == currDoW) { sum = sum + this->getStepsToday(); } - sum = sum + this->_stepsCache[i]; + sum = sum + this->_stepsCache[i]; } return sum; #else From 232628d3b247cc55c86aa13c24a1601c8ab08be7 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sat, 11 Jun 2022 00:55:48 +0900 Subject: [PATCH 013/116] Readme : correct expression --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index a1237261c..330271642 100644 --- a/Readme.md +++ b/Readme.md @@ -63,7 +63,7 @@ http:///api/screenserver The `fetchScreen.sh` downloads the raw image buffer from the running screen server, and converts the image to png. The `composeScreen.sh` creates the image with a surrounding smartwatch (light edition). -#### Quick-Fast (recommend) +#### The fast way(recommended) ``` $ cd open-smartwatch-os/ $ ./createScreenshot.sh From 01ac7a51258572b9e7ac468405b107b8ce7900d3 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sat, 11 Jun 2022 02:03:11 +0900 Subject: [PATCH 014/116] Readme : update readme -usage script --- Readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 330271642..2ccee3043 100644 --- a/Readme.md +++ b/Readme.md @@ -64,8 +64,10 @@ http:///api/screenserver The `fetchScreen.sh` downloads the raw image buffer from the running screen server, and converts the image to png. The `composeScreen.sh` creates the image with a surrounding smartwatch (light edition). #### The fast way(recommended) + +Run the following inside the `open-smartwatch-os` directory: + ``` -$ cd open-smartwatch-os/ $ ./createScreenshot.sh ``` * You can check the files you captured in the `screenshot/` folder. From c94f53d25a71c2c853e24d155304feb1a7f18b01 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sat, 11 Jun 2022 15:57:13 +0900 Subject: [PATCH 015/116] scripts : rename directory --- {screenshotScript => scripts}/composeScreen.sh | 0 {screenshotScript => scripts}/fetchScreen.sh | 0 .../screenshot-overlay-mask.png | Bin .../screenshot-overlay.png | Bin 4 files changed, 0 insertions(+), 0 deletions(-) rename {screenshotScript => scripts}/composeScreen.sh (100%) rename {screenshotScript => scripts}/fetchScreen.sh (100%) rename {screenshotScript => scripts}/screenshot-overlay-mask.png (100%) rename {screenshotScript => scripts}/screenshot-overlay.png (100%) diff --git a/screenshotScript/composeScreen.sh b/scripts/composeScreen.sh similarity index 100% rename from screenshotScript/composeScreen.sh rename to scripts/composeScreen.sh diff --git a/screenshotScript/fetchScreen.sh b/scripts/fetchScreen.sh similarity index 100% rename from screenshotScript/fetchScreen.sh rename to scripts/fetchScreen.sh diff --git a/screenshotScript/screenshot-overlay-mask.png b/scripts/screenshot-overlay-mask.png similarity index 100% rename from screenshotScript/screenshot-overlay-mask.png rename to scripts/screenshot-overlay-mask.png diff --git a/screenshotScript/screenshot-overlay.png b/scripts/screenshot-overlay.png similarity index 100% rename from screenshotScript/screenshot-overlay.png rename to scripts/screenshot-overlay.png From dc795600be83d4afe1198c5a53f4d803896b9bdf Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sat, 11 Jun 2022 16:18:00 +0900 Subject: [PATCH 016/116] scripts : move path --- update.sh => scripts/update_sync/update.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename update.sh => scripts/update_sync/update.sh (100%) diff --git a/update.sh b/scripts/update_sync/update.sh similarity index 100% rename from update.sh rename to scripts/update_sync/update.sh From bbfde3ef93b737576ef507f821c00a900baefe0d Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sat, 11 Jun 2022 16:18:39 +0900 Subject: [PATCH 017/116] Readme : change usage screenshot-script --- Readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 2ccee3043..c695a5e14 100644 --- a/Readme.md +++ b/Readme.md @@ -68,9 +68,10 @@ The `fetchScreen.sh` downloads the raw image buffer from the running screen serv Run the following inside the `open-smartwatch-os` directory: ``` +$ cd scripts/screen_capture/ $ ./createScreenshot.sh ``` -* You can check the files you captured in the `screenshot/` folder. +* The captured file can be found in the `screenshot/` folder inside the `open-smartwatch-os` directory. ## Troubleshooting ### Arduino_TFT.h: No such file or directory From d625a2516f514ac071cfa9dfe1beb10c054a59a0 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sat, 11 Jun 2022 16:21:15 +0900 Subject: [PATCH 018/116] scripts : create screen-capture directory --- scripts/composeScreen.sh | 25 ------------------ scripts/screen_capture/composeScreen.sh | 25 ++++++++++++++++++ .../screen_capture/createScreenshot.sh | 4 +-- scripts/{ => screen_capture}/fetchScreen.sh | 0 .../screenshot-overlay-mask.png | Bin .../screenshot-overlay.png | Bin 6 files changed, 27 insertions(+), 27 deletions(-) delete mode 100755 scripts/composeScreen.sh create mode 100755 scripts/screen_capture/composeScreen.sh rename createScreenshot.sh => scripts/screen_capture/createScreenshot.sh (54%) rename scripts/{ => screen_capture}/fetchScreen.sh (100%) rename scripts/{ => screen_capture}/screenshot-overlay-mask.png (100%) rename scripts/{ => screen_capture}/screenshot-overlay.png (100%) diff --git a/scripts/composeScreen.sh b/scripts/composeScreen.sh deleted file mode 100755 index 85d3f73b7..000000000 --- a/scripts/composeScreen.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -if [ -z "$1" ] || [ -z "$2" ]; -then - echo "usage: composeScreen.sh " - exit -fi - -TEMPFILE=temp.png - -convert -composite -gravity center screenshotScript/screenshot-overlay.png $1 $TEMPFILE -if [ ! -d screenshots/ ]; -then - mkdir screenshots/ -fi -convert -composite -gravity center screenshotScript/screenshot-overlay.png $TEMPFILE screenshotScript/screenshot-overlay-mask.png screenshots/$2 - -if [ -f $TEMPFILE ]; -then - rm $TEMPFILE -fi -if [ -f $1 ]; -then - rm $1 -fi diff --git a/scripts/screen_capture/composeScreen.sh b/scripts/screen_capture/composeScreen.sh new file mode 100755 index 000000000..f934fd6ba --- /dev/null +++ b/scripts/screen_capture/composeScreen.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +if [ -z "$1" ] || [ -z "$2" ]; +then + echo "usage: composeScreen.sh " + exit +fi + +TEMPFILE=temp.png + +convert -composite -gravity center screenshot-overlay.png $1 $TEMPFILE +if [ ! -d ../../screenshots/ ]; +then + mkdir ../../screenshots/ +fi +convert -composite -gravity center screenshot-overlay.png $TEMPFILE screenshot-overlay-mask.png ../../screenshots/$2 + +if [ -f $TEMPFILE ]; +then + rm $TEMPFILE +fi +if [ -f $1 ]; +then + rm $1 +fi diff --git a/createScreenshot.sh b/scripts/screen_capture/createScreenshot.sh similarity index 54% rename from createScreenshot.sh rename to scripts/screen_capture/createScreenshot.sh index 30fb68bc7..212141144 100755 --- a/createScreenshot.sh +++ b/scripts/screen_capture/createScreenshot.sh @@ -6,6 +6,6 @@ then exit fi -bash screenshotScript/fetchScreen.sh $1 $2.png +bash fetchScreen.sh $1 $2.png -bash screenshotScript/composeScreen.sh $2.png $2_osw.png +bash composeScreen.sh $2.png $2_osw.png diff --git a/scripts/fetchScreen.sh b/scripts/screen_capture/fetchScreen.sh similarity index 100% rename from scripts/fetchScreen.sh rename to scripts/screen_capture/fetchScreen.sh diff --git a/scripts/screenshot-overlay-mask.png b/scripts/screen_capture/screenshot-overlay-mask.png similarity index 100% rename from scripts/screenshot-overlay-mask.png rename to scripts/screen_capture/screenshot-overlay-mask.png diff --git a/scripts/screenshot-overlay.png b/scripts/screen_capture/screenshot-overlay.png similarity index 100% rename from scripts/screenshot-overlay.png rename to scripts/screen_capture/screenshot-overlay.png From 43c25465f7438ab52e31952f6b9b5e1b3151a387 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sat, 11 Jun 2022 16:30:31 +0900 Subject: [PATCH 019/116] scripts : move path --- install.py => scripts/build_install/install.py | 0 .../build_install/prebuild_cppflags.py | 0 prebuild_info.py => scripts/build_install/prebuild_info.py | 0 prebuild_lua.py => scripts/build_install/prebuild_lua.py | 0 prebuild_www.py => scripts/build_install/prebuild_www.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename install.py => scripts/build_install/install.py (100%) rename prebuild_cppflags.py => scripts/build_install/prebuild_cppflags.py (100%) rename prebuild_info.py => scripts/build_install/prebuild_info.py (100%) rename prebuild_lua.py => scripts/build_install/prebuild_lua.py (100%) rename prebuild_www.py => scripts/build_install/prebuild_www.py (100%) diff --git a/install.py b/scripts/build_install/install.py similarity index 100% rename from install.py rename to scripts/build_install/install.py diff --git a/prebuild_cppflags.py b/scripts/build_install/prebuild_cppflags.py similarity index 100% rename from prebuild_cppflags.py rename to scripts/build_install/prebuild_cppflags.py diff --git a/prebuild_info.py b/scripts/build_install/prebuild_info.py similarity index 100% rename from prebuild_info.py rename to scripts/build_install/prebuild_info.py diff --git a/prebuild_lua.py b/scripts/build_install/prebuild_lua.py similarity index 100% rename from prebuild_lua.py rename to scripts/build_install/prebuild_lua.py diff --git a/prebuild_www.py b/scripts/build_install/prebuild_www.py similarity index 100% rename from prebuild_www.py rename to scripts/build_install/prebuild_www.py From c2bc4246b4884b2c288b73e4f17d84205646c4d4 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sat, 11 Jun 2022 16:43:44 +0900 Subject: [PATCH 020/116] Platformio : change path (python script) --- platformio.ini | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/platformio.ini b/platformio.ini index faa11e24a..b7d2a2b79 100755 --- a/platformio.ini +++ b/platformio.ini @@ -35,9 +35,9 @@ upload_speed = 460800 monitor_speed = 115200 ; Define additional build stage scripts - used to "compile" the html or define additional information extra_scripts = - pre:prebuild_info.py - pre:prebuild_www.py - pre:prebuild_cppflags.py + pre:scripts/build_install/prebuild_info.py + pre:scripts/build_install/prebuild_www.py + pre:scripts/build_install/prebuild_cppflags.py ; Light edition by hardware revisions [env:LIGHT_EDITION_V3_2] @@ -66,10 +66,10 @@ build_flags = -D OSW_FEATURE_WIFI -D LUA_C89_NUMBERS ; Required by OSW_FEATURE_LUA extra_scripts = - pre:prebuild_info.py - pre:prebuild_www.py - pre:prebuild_cppflags.py - pre:prebuild_lua.py ; Needed to generate the .cxx file(s) + pre:scripts/build_install/prebuild_info.py + pre:scripts/build_install/prebuild_www.py + pre:scripts/build_install/prebuild_cppflags.py + pre:scripts/build_install/prebuild_lua.py ; Needed to generate the .cxx file(s) build_type = debug ; GPS edition by hardware revisions From c658def8ac475d8867fddf51b2a29de066d3e0e4 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sun, 12 Jun 2022 17:54:18 +0900 Subject: [PATCH 021/116] Readme : remove line change --- Readme.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index c695a5e14..742598526 100644 --- a/Readme.md +++ b/Readme.md @@ -40,8 +40,7 @@ depending on the watch model. ## Creating Screen Shots of your Apps - - + * Wifi needs to be able to connect for this to work. * you will need bash and imagemagick for the helper scripts to work From f1ad05060c86e9c100e5d6f6abb710c9bbc5ba13 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Tue, 14 Jun 2022 09:35:38 +0900 Subject: [PATCH 022/116] Apps : refactoring variable value --- include/apps/watchfaces/OswAppWatchfaceDual.h | 2 +- src/apps/tools/OswAppKcalStats.cpp | 19 +++++------ src/apps/tools/OswAppStepStats.cpp | 34 +++++++++---------- src/apps/watchfaces/OswAppWatchfaceDual.cpp | 9 ++--- .../watchfaces/OswAppWatchfaceFitness.cpp | 18 +++++----- src/apps/watchfaces/OswAppWatchfaceMix.cpp | 28 ++++++++------- 6 files changed, 54 insertions(+), 56 deletions(-) diff --git a/include/apps/watchfaces/OswAppWatchfaceDual.h b/include/apps/watchfaces/OswAppWatchfaceDual.h index a06bd05d0..f35815af5 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDual.h +++ b/include/apps/watchfaces/OswAppWatchfaceDual.h @@ -18,7 +18,7 @@ class OswAppWatchfaceDual : public OswApp { //for dual-time static void drawProgressBar(OswUI* ui,uint8_t cx, uint8_t cy, uint8_t jump, uint8_t length, uint8_t value,float angle, uint8_t radius, uint16_t color, uint8_t* goal=nullptr); - void drawAnim(); + void drawAnimSec(); private: OswUI* ui; diff --git a/src/apps/tools/OswAppKcalStats.cpp b/src/apps/tools/OswAppKcalStats.cpp index 2e2dcf014..22a74ca63 100644 --- a/src/apps/tools/OswAppKcalStats.cpp +++ b/src/apps/tools/OswAppKcalStats.cpp @@ -71,32 +71,31 @@ void OswAppKcalStats::showCurvedChart() { uint8_t coordX = 30; hal->gfx()->drawThickTick(coordX, 150, 0, 240 - (coordX * 2), 90, 2, ui->getPrimaryColor()); - hal->gfx()->drawLine(DISP_W / 2, 150 + 15, 120, 220, ui->getPrimaryColor()); + hal->gfx()->drawLine(DISP_W / 2, 165, 120, 220, ui->getPrimaryColor()); // Data info uint32_t wDay = findCursorWeekDay(this->cursorPos); hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextBottomAligned(); - hal->gfx()->setTextColor(ui->getForegroundColor()); hal->gfx()->setTextCenterAligned(); - hal->gfx()->setTextCursor(80, 140 + 25); + hal->gfx()->setTextCursor(80, 165); hal->gfx()->print(LANG_KCAL_AVG); - hal->gfx()->setTextCursor(160, 140 + 25); + hal->gfx()->setTextCursor(160, 165); hal->gfx()->print(hal->getLocalWeekday(&wDay)); hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor(DISP_W / 2 - 7, 160 + 25); + hal->gfx()->setTextCursor(DISP_W / 2 - 7, 185); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()) / 7 )); - hal->gfx()->setTextCursor(DISP_W / 2 - 7, 160 + 25 + 10); + hal->gfx()->setTextCursor(DISP_W / 2 - 7, 195); hal->gfx()->print(hal->environment->getStepsTotalWeek()/7); // total step counter - hal->gfx()->setTextCursor(DISP_W / 2 - 7, 160 + 25 + 20); + hal->gfx()->setTextCursor(DISP_W / 2 - 7, 205); hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek())/7); // total step counter hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(DISP_W / 2 + 7, 160 + 25); + hal->gfx()->setTextCursor(DISP_W / 2 + 7, 185); hal->gfx()->print(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(wDay))+String(" m")); - hal->gfx()->setTextCursor(DISP_W / 2 + 7, 160 + 25 + 10); + hal->gfx()->setTextCursor(DISP_W / 2 + 7, 195); hal->gfx()->print(hal->environment->getStepsOnDay(wDay) + String(" ") + String(LANG_KCAL_STEP)); // total step counter - hal->gfx()->setTextCursor(DISP_W / 2 + 7, 160 + 25 + 20); + hal->gfx()->setTextCursor(DISP_W / 2 + 7, 205); hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDay(wDay))+String(" kcal")); // total step counter } diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index 4cbf42c3d..882175030 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -28,9 +28,9 @@ void OswAppStepStats::drawChart() { // step bars if (index == weekDay) { - hal->gfx()->drawThickTick(60 + index * interval, 150 - 3, 0, chartStickHeight, 0, 5, ui->getForegroundColor()); + hal->gfx()->drawThickTick(60 + index * interval, 147, 0, chartStickHeight, 0, 5, ui->getForegroundColor()); } - hal->gfx()->drawThickTick(60 + index * interval, 150 - 3, 0, chartStickValue, 0, 3, barColor, true); + hal->gfx()->drawThickTick(60 + index * interval, 147, 0, chartStickValue, 0, 3, barColor, true); } } @@ -50,30 +50,30 @@ void OswAppStepStats::showStickChart() { uint8_t coord_x = 30; hal->gfx()->drawThickTick(coord_x, 150, 0, 240 - (coord_x * 2), 90, 2, ui->getPrimaryColor()); - hal->gfx()->drawLine(120, 150 + 15, 120, 220, ui->getPrimaryColor()); // long front + hal->gfx()->drawLine(120, 165, 120, 220, ui->getPrimaryColor()); // long front hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextBottomAligned(); - hal->gfx()->setTextCursor(80, 140 + 25); - hal->gfx()->print(LANG_STEPSTATS_TOTAL); // total step counter - hal->gfx()->setTextCursor(160, 140 + 25); - hal->gfx()->print(LANG_STEPSTATS_TODAY); // total step counter + hal->gfx()->setTextCursor(80, 165); + hal->gfx()->print(LANG_STEPSTATS_TOTAL); + hal->gfx()->setTextCursor(160, 165); + hal->gfx()->print(LANG_STEPSTATS_TODAY); hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor(120 - 7, 160 + 25); + hal->gfx()->setTextCursor(DISP_W / 2 - 7, 185); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()))); - hal->gfx()->setTextCursor(120 - 7, 160 + 25 + 10); - hal->gfx()->print(hal->environment->getStepsTotalWeek() ); // total step counter - hal->gfx()->setTextCursor(120 - 7, 160 + 25 + 20); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek()) ); // total step counter + hal->gfx()->setTextCursor(DISP_W / 2 - 7, 195); + hal->gfx()->print(hal->environment->getStepsTotalWeek() ); + hal->gfx()->setTextCursor(DISP_W / 2 - 7, 205); + hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek()) ); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(120 + 7, 160 + 25); + hal->gfx()->setTextCursor(DISP_W / 2 + 7, 185); hal->gfx()->print(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsToday())+String(" m")); - hal->gfx()->setTextCursor(120 + 7, 160 + 25 + 10); - hal->gfx()->print(hal->environment->getStepsToday() +String(" ")+ String(LANG_STEPSTATS_STEP)); // total step counter - hal->gfx()->setTextCursor(120 + 7, 160 + 25 + 20); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsToday())+String(" kcal")); // total step counter + hal->gfx()->setTextCursor(DISP_W / 2 + 7, 195); + hal->gfx()->print(hal->environment->getStepsToday() +String(" ")+ String(LANG_STEPSTATS_STEP)); + hal->gfx()->setTextCursor(DISP_W / 2 + 7, 205); + hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsToday())+String(" kcal")); } void OswAppStepStats::setup() {} diff --git a/src/apps/watchfaces/OswAppWatchfaceDual.cpp b/src/apps/watchfaces/OswAppWatchfaceDual.cpp index 4e7d45496..66af5bc54 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDual.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDual.cpp @@ -29,17 +29,14 @@ void OswAppWatchfaceDual::drawProgressBar(OswUI* ui,uint8_t cx, uint8_t cy, uint hal->gfx()->drawThickTick(cx, cy, jump, value, angle, radius, goal == nullptr ? color :*goalgetSuccessColor():color, true); } -void OswAppWatchfaceDual::drawAnim() { +void OswAppWatchfaceDual::drawAnimSec() { OswHal* hal = OswHal::getInstance(); - uint8_t barWidth = 140; - uint32_t Hs, Ms, Ss = 0; hal->getLocalTime(&Hs,&Ms,&Ss); - uint32_t onlySecond = Ss; // virtual step simulation + uint32_t onlySecond = Ss; uint16_t barValue = ((float)(onlySecond > 60 ? 60 : onlySecond) / 60) * barWidth; barValue = barValue < 2 ? 0 : barValue; - uint8_t coordX = (DISP_W - barWidth) / 2; uint8_t levelY = DISP_H / 2; uint8_t radius = 1.5; @@ -67,7 +64,7 @@ void OswAppWatchfaceDual::loop() { OswAppWatchfaceDigital::digitalWatch(OswConfigAllKeys::timeZone.get(),1, 120 - mid_little, 120 - mid); OswAppWatchfaceDigital::digitalWatch(OswConfigAllKeys::dualTimeZone.get(),1, 120 + mid_little, 120 + mid); - drawAnim(); + drawAnimSec(); #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 OswAppWatchfaceDigital::drawSteps(); diff --git a/src/apps/watchfaces/OswAppWatchfaceFitness.cpp b/src/apps/watchfaces/OswAppWatchfaceFitness.cpp index 0b2792c18..11c4d33cf 100644 --- a/src/apps/watchfaces/OswAppWatchfaceFitness.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceFitness.cpp @@ -47,7 +47,7 @@ void dateDisplay() { hal->gfx()->setTextSize(2); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(120 - 30 + hal->gfx()->getTextOfsetColumns(1), 150); + hal->gfx()->setTextCursor(DISP_W/2 - 30 + hal->gfx()->getTextOfsetColumns(1), 150); OswAppWatchfaceDigital::dateOutput(yearInt, monthInt, dayInt); } @@ -60,7 +60,7 @@ void timeDisplay(uint32_t hour, uint32_t minute, uint32_t second) { hal->gfx()->setTextSize(1); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(215, 120); + hal->gfx()->setTextCursor(215, DISP_W/2); hal->gfx()->printDecimal(second,2); } @@ -76,7 +76,7 @@ void digitalWatchDisplay() { hal->gfx()->setTextSize(4); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(120 - 30, 120); + hal->gfx()->setTextCursor(DISP_W/2 - 30, DISP_W/2); hal->getLocalTime(&hour, &minute, &second, &afterNoon); @@ -118,27 +118,27 @@ void OswAppWatchfaceFitness::showFitnessTracking() { hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextColor(dimColor(ui->getDangerColor(), 25)); - hal->gfx()->setTextCursor(120 + 10, 25); + hal->gfx()->setTextCursor(DISP_W/2 + 10, 25); hal->gfx()->print(steps); hal->gfx()->setTextColor(dimColor(ui->getWarningColor(), 25)); - hal->gfx()->setTextCursor(120 + 10, 45); + hal->gfx()->setTextCursor(DISP_W/2 + 10, 45); hal->gfx()->print(kcals); hal->gfx()->setTextColor(dimColor(ui->getInfoColor(), 25)); - hal->gfx()->setTextCursor(120 + 10, 65); + hal->gfx()->setTextCursor(DISP_W/2 + 10, 65); hal->gfx()->print(dists); hal->gfx()->setTextColor(dimColor(ui->getInfoColor(), 25)); - hal->gfx()->setTextCursor(120 + 10, 180 - 5); + hal->gfx()->setTextCursor(DISP_W/2 + 10, DISP_H-65); hal->gfx()->print(LANG_WATCHFACE_FITNESS_DISTANCE); hal->gfx()->setTextColor(dimColor(ui->getWarningColor(), 25)); - hal->gfx()->setTextCursor(120 + 10, 200 - 5); + hal->gfx()->setTextCursor(DISP_W/2 + 10, DISP_H-45); hal->gfx()->print("kcal"); hal->gfx()->setTextColor(dimColor(ui->getDangerColor(), 25)); - hal->gfx()->setTextCursor(120 + 10, 220 - 5); + hal->gfx()->setTextCursor(DISP_W/2 + 10, DISP_H-25); hal->gfx()->print(LANG_WATCHFACE_FITNESS_STEP); } void OswAppWatchfaceFitness::setup() {} diff --git a/src/apps/watchfaces/OswAppWatchfaceMix.cpp b/src/apps/watchfaces/OswAppWatchfaceMix.cpp index af009943c..cc8baaa2e 100644 --- a/src/apps/watchfaces/OswAppWatchfaceMix.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceMix.cpp @@ -10,6 +10,9 @@ #include #include +#define OFF_SET_ANALOG_WATCH_X_COORD 62 // need to set coord, Use this part to move to the x-axis. +#define OFF_SET_DATE_DIGITAL_WATCH_X_COORD 7 // need to set coord, Use this part to move to the x-axis. + void OswAppWatchfaceMix::analogWatchDisplay() { OswHal* hal = OswHal::getInstance(); uint32_t second = 0; @@ -17,16 +20,16 @@ void OswAppWatchfaceMix::analogWatchDisplay() { uint32_t hour = 0; // Unused, but required by function signature hal->getLocalTime(&hour, &minute, &second); - hal->gfx()->drawCircle((int)(DISP_W*0.5)-62, 100, 50, ui->getForegroundColor()); - hal->gfx()->drawHourTicks((int)(DISP_W*0.5)-62, 100, 45, 40, ui->getForegroundDimmedColor()); + hal->gfx()->drawCircle((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, 50, ui->getForegroundColor()); + hal->gfx()->drawHourTicks((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, 45, 40, ui->getForegroundDimmedColor()); // hour - hal->gfx()->drawLine((int)(DISP_W*0.5)-62, 100, rpx((int)(DISP_W*0.5)-62, (int)(33 * 0.5), hour * 30 + (int)( minute* 0.1 ) * 6), rpy(100, (int)(33 * 0.5), hour * 30 + (int)( minute* 0.1 ) * 6 ), ui->getForegroundColor()); - // // minute - hal->gfx()->drawLine((int)(DISP_W*0.5)-62, 100, rpx((int)(DISP_W*0.5)-62, (int)(66 * 0.5), minute * 6), rpy(100, (int)(66 * 0.5), minute * 6), ui->getSuccessColor()); - // // second - hal->gfx()->drawLine((int)(DISP_W*0.5)-62, 100, rpx((int)(DISP_W*0.5)-62, (int)(15 * 0.5), s2d(second) + 180), rpy(100, (int)(15 * 0.5), s2d(second) + 180), ui->getDangerColor()); // short backwards - hal->gfx()->drawLine((int)(DISP_W*0.5)-62, 100, rpx((int)(DISP_W*0.5)-62, (int)(90 * 0.5), s2d(second)), rpy(100, (int)(90 * 0.5), s2d(second)), ui->getDangerColor()); // long front + hal->gfx()->drawLine((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, rpx((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, (int)(33 * 0.5), hour * 30 + (int)( minute* 0.1 ) * 6), rpy(100, (int)(33 * 0.5), hour * 30 + (int)( minute* 0.1 ) * 6 ), ui->getForegroundColor()); + // minute + hal->gfx()->drawLine((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, rpx((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, (int)(66 * 0.5), minute * 6), rpy(100, (int)(66 * 0.5), minute * 6), ui->getSuccessColor()); + // second + hal->gfx()->drawLine((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, rpx((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, (int)(15 * 0.5), s2d(second) + 180), rpy(100, (int)(15 * 0.5), s2d(second) + 180), ui->getDangerColor()); // short backwards + hal->gfx()->drawLine((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, 100, rpx((int)(DISP_W*0.5)-OFF_SET_ANALOG_WATCH_X_COORD, (int)(90 * 0.5), s2d(second)), rpy(100, (int)(90 * 0.5), s2d(second)), ui->getDangerColor()); // long front } void OswAppWatchfaceMix::dateDisplay() { @@ -43,7 +46,7 @@ void OswAppWatchfaceMix::dateDisplay() { hal->gfx()->setTextSize(1); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(120-7, 75); + hal->gfx()->setTextCursor(120-OFF_SET_DATE_DIGITAL_WATCH_X_COORD, 75); { char weekday3[4]; @@ -64,7 +67,7 @@ void OswAppWatchfaceMix::dateDisplay() { hal->gfx()->setTextSize(2); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(120-7, 90); + hal->gfx()->setTextCursor(120-OFF_SET_DATE_DIGITAL_WATCH_X_COORD, 90); // i really would want the date to be dynamic based on what's in the config, but the most efficient thing to do right // now is simply three if statements covering the 3 common conditions. @@ -83,7 +86,7 @@ void OswAppWatchfaceMix::digitalWatchDisplay() { hal->gfx()->setTextSize(3); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(120-7, 120); + hal->gfx()->setTextCursor(120-OFF_SET_DATE_DIGITAL_WATCH_X_COORD, 120); hal->getLocalTime(&hour, &minute, &second, &afterNoon); OswAppWatchfaceDigital::timeOutput(hour, minute, second,false); @@ -93,9 +96,8 @@ void OswAppWatchfaceMix::digitalWatchDisplay() { hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextBottomAligned(); hal->gfx()->setTextSize(3); - hal->gfx()->setTextCursor(120-7 + hal->gfx()->getTextOfsetColumns(5.25), 120 + 10); + hal->gfx()->setTextCursor(120-OFF_SET_DATE_DIGITAL_WATCH_X_COORD + hal->gfx()->getTextOfsetColumns(5.25), 130); hal->gfx()->setTextSize(1); - hal->gfx()->print(" "); if (afterNoon) { hal->gfx()->print(pm); From d54ba79acd2d08a7b11040c67bd7f1fc0d6075d0 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Tue, 14 Jun 2022 09:55:10 +0900 Subject: [PATCH 023/116] Apps : refactoring lib-header --- include/apps/tools/OswAppFitnessStats.h | 8 ++------ include/apps/tools/OswAppKcalStats.h | 8 ++------ include/apps/tools/OswAppStepStats.h | 8 ++------ include/apps/tools/OswAppWebserver.h | 6 +----- include/apps/tools/ble_media_ctrl.h | 8 ++------ include/apps/tools/button_test.h | 8 ++------ include/apps/tools/print_debug.h | 8 ++------ include/apps/tools/time_config.h | 8 ++------ include/apps/tools/water_level.h | 8 ++------ include/apps/watchfaces/OswAppWatchface.h | 7 ++----- include/apps/watchfaces/OswAppWatchfaceBinary.h | 7 ++----- include/apps/watchfaces/OswAppWatchfaceDigital.h | 7 ++----- include/apps/watchfaces/OswAppWatchfaceDual.h | 7 ++----- include/apps/watchfaces/OswAppWatchfaceFitness.h | 5 +---- include/apps/watchfaces/OswAppWatchfaceMix.h | 5 +---- 15 files changed, 27 insertions(+), 81 deletions(-) diff --git a/include/apps/tools/OswAppFitnessStats.h b/include/apps/tools/OswAppFitnessStats.h index 3fddd48e7..5d09a7ffc 100644 --- a/include/apps/tools/OswAppFitnessStats.h +++ b/include/apps/tools/OswAppFitnessStats.h @@ -1,9 +1,7 @@ -#ifndef OSW_APP_FITNESS_STATS_H -#define OSW_APP_FITNESS_STATS_H +#pragma once #include #include - #include "osw_app.h" class OswAppFitnessStats : public OswApp { @@ -19,6 +17,4 @@ class OswAppFitnessStats : public OswApp { private: OswUI* ui; -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/include/apps/tools/OswAppKcalStats.h b/include/apps/tools/OswAppKcalStats.h index 9bee0f0a0..de8e9731f 100644 --- a/include/apps/tools/OswAppKcalStats.h +++ b/include/apps/tools/OswAppKcalStats.h @@ -1,9 +1,7 @@ -#ifndef OSW_APP_KCAL_STATS_H -#define OSW_APP_KCAL_STATS_H +#pragma once #include #include - #include "osw_app.h" class OswAppKcalStats : public OswApp { @@ -21,6 +19,4 @@ class OswAppKcalStats : public OswApp { void drawCurvedChart(); void showCurvedChart(); OswUI* ui; -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/include/apps/tools/OswAppStepStats.h b/include/apps/tools/OswAppStepStats.h index 759784b78..fd4874887 100644 --- a/include/apps/tools/OswAppStepStats.h +++ b/include/apps/tools/OswAppStepStats.h @@ -1,9 +1,7 @@ -#ifndef OSW_APP_STEP_STATS_H -#define OSW_APP_STEP_STATS_H +#pragma once #include #include - #include "osw_app.h" class OswAppStepStats : public OswApp { @@ -20,6 +18,4 @@ class OswAppStepStats : public OswApp { void showStickChart(); void drawChart(); OswUI* ui; -}; - -#endif +}; \ No newline at end of file diff --git a/include/apps/tools/OswAppWebserver.h b/include/apps/tools/OswAppWebserver.h index 3bea727b7..1149ba1cf 100644 --- a/include/apps/tools/OswAppWebserver.h +++ b/include/apps/tools/OswAppWebserver.h @@ -1,10 +1,8 @@ #ifdef OSW_FEATURE_WIFI -#ifndef OSW_APP_CONFIG_MGMT_H -#define OSW_APP_CONFIG_MGMT_H +#pragma once #include #include - #include "osw_app.h" class OswAppWebserver : public OswApp { @@ -20,6 +18,4 @@ class OswAppWebserver : public OswApp { private: OswUI* ui; }; - -#endif #endif \ No newline at end of file diff --git a/include/apps/tools/ble_media_ctrl.h b/include/apps/tools/ble_media_ctrl.h index 8e773f1eb..dcf388fe3 100644 --- a/include/apps/tools/ble_media_ctrl.h +++ b/include/apps/tools/ble_media_ctrl.h @@ -1,8 +1,6 @@ -#ifndef OSW_APP_BLE_MEDIA_CTRL_H -#define OSW_APP_BLE_MEDIA_CTRL_H +#pragma once #include - #include "osw_app.h" class OswAppBLEMEdiaCtrl : public OswApp { @@ -14,6 +12,4 @@ class OswAppBLEMEdiaCtrl : public OswApp { ~OswAppBLEMEdiaCtrl() {}; private: -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/include/apps/tools/button_test.h b/include/apps/tools/button_test.h index 247f7abae..6b166c1b6 100644 --- a/include/apps/tools/button_test.h +++ b/include/apps/tools/button_test.h @@ -1,8 +1,6 @@ -#ifndef OSW_BUTTON_TEST_H -#define OSW_BUTTON_TEST_H +#pragma once #include - #include "osw_app.h" class OswButtonTest : public OswApp { @@ -21,6 +19,4 @@ class OswButtonTest : public OswApp { const char* longPress = "Long Press"; uint8_t lastButton = 255; -}; - -#endif +}; \ No newline at end of file diff --git a/include/apps/tools/print_debug.h b/include/apps/tools/print_debug.h index 0027cf6df..8d326e8c1 100644 --- a/include/apps/tools/print_debug.h +++ b/include/apps/tools/print_debug.h @@ -1,8 +1,6 @@ -#ifndef OSW_APP_PRINT_DEBUG_H -#define OSW_APP_PRINT_DEBUG_H +#pragma once #include - #include "osw_app.h" class OswAppPrintDebug : public OswApp { @@ -14,6 +12,4 @@ class OswAppPrintDebug : public OswApp { ~OswAppPrintDebug() {}; private: -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/include/apps/tools/time_config.h b/include/apps/tools/time_config.h index 71742c6c6..091772621 100644 --- a/include/apps/tools/time_config.h +++ b/include/apps/tools/time_config.h @@ -1,10 +1,8 @@ -#ifndef OSW_APP_TIME_FROM_WEB_H -#define OSW_APP_TIME_FROM_WEB_H +#pragma once #include #include #include "apps/main/switcher.h" - #include "osw_app.h" class OswAppTimeConfig : public OswApp { @@ -28,6 +26,4 @@ class OswAppTimeConfig : public OswApp { int16_t manualSettingTimestamp[11]; OswUI* ui = nullptr; OswAppSwitcher* settingsAppSwitcher = nullptr; -}; - -#endif +}; \ No newline at end of file diff --git a/include/apps/tools/water_level.h b/include/apps/tools/water_level.h index 3ffe80727..e291314f4 100644 --- a/include/apps/tools/water_level.h +++ b/include/apps/tools/water_level.h @@ -1,9 +1,7 @@ -#ifndef OSW_APP_WATER_LEVEL_H -#define OSW_APP_WATER_LEVEL_H +#pragma once #include #include - #include "osw_app.h" class OswAppWaterLevel : public OswApp { @@ -22,6 +20,4 @@ class OswAppWaterLevel : public OswApp { private: OswUI* ui; -}; - -#endif +}; \ No newline at end of file diff --git a/include/apps/watchfaces/OswAppWatchface.h b/include/apps/watchfaces/OswAppWatchface.h index cadc1de0c..9c40b8383 100644 --- a/include/apps/watchfaces/OswAppWatchface.h +++ b/include/apps/watchfaces/OswAppWatchface.h @@ -1,5 +1,4 @@ -#ifndef OSW_APP_WATCHFACE_H -#define OSW_APP_WATCHFACE_H +#pragma once #include #include @@ -28,6 +27,4 @@ class OswAppWatchface : public OswApp { #ifdef MATRIX AnimMatrix* matrix; #endif -}; - -#endif +}; \ No newline at end of file diff --git a/include/apps/watchfaces/OswAppWatchfaceBinary.h b/include/apps/watchfaces/OswAppWatchfaceBinary.h index d00cf03ea..521178bb2 100644 --- a/include/apps/watchfaces/OswAppWatchfaceBinary.h +++ b/include/apps/watchfaces/OswAppWatchfaceBinary.h @@ -1,5 +1,4 @@ -#ifndef OSW_APP_WATCHFACE_BINARY_H -#define OSW_APP_WATCHFACE_BINARY_H +#pragma once #include #include @@ -20,6 +19,4 @@ class OswAppWatchfaceBinary : public OswApp { uint16_t primaryColor; void drawWatch(Graphics2D* gfx2d); OswUI* ui; -}; - -#endif +}; \ No newline at end of file diff --git a/include/apps/watchfaces/OswAppWatchfaceDigital.h b/include/apps/watchfaces/OswAppWatchfaceDigital.h index 183d1d05e..3905561fb 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDigital.h +++ b/include/apps/watchfaces/OswAppWatchfaceDigital.h @@ -1,5 +1,4 @@ -#ifndef OSW_APP_WATCHFACE_DIGITAL_H -#define OSW_APP_WATCHFACE_DIGITAL_H +#pragma once #include #include @@ -23,6 +22,4 @@ class OswAppWatchfaceDigital : public OswApp { private: OswUI* ui; -}; - -#endif +}; \ No newline at end of file diff --git a/include/apps/watchfaces/OswAppWatchfaceDual.h b/include/apps/watchfaces/OswAppWatchfaceDual.h index a06bd05d0..34cf8f87b 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDual.h +++ b/include/apps/watchfaces/OswAppWatchfaceDual.h @@ -1,5 +1,4 @@ -#ifndef OSW_APP_WATCHFACE_DUAL_H -#define OSW_APP_WATCHFACE_DUAL_H +#pragma once #include #include @@ -23,6 +22,4 @@ class OswAppWatchfaceDual : public OswApp { private: OswUI* ui; // Blank to make the 2 clocks easier to recognize -}; - -#endif +}; \ No newline at end of file diff --git a/include/apps/watchfaces/OswAppWatchfaceFitness.h b/include/apps/watchfaces/OswAppWatchfaceFitness.h index 47b94bc81..6593c165b 100644 --- a/include/apps/watchfaces/OswAppWatchfaceFitness.h +++ b/include/apps/watchfaces/OswAppWatchfaceFitness.h @@ -1,5 +1,4 @@ -#ifndef OSW_APP_WATCHFACE_FITNESS_H -#define OSW_APP_WATCHFACE_FITNESS_H +#pragma once #include #include @@ -22,5 +21,3 @@ class OswAppWatchfaceFitness : public OswApp { void showFitnessTracking(); OswUI* ui; }; - -#endif diff --git a/include/apps/watchfaces/OswAppWatchfaceMix.h b/include/apps/watchfaces/OswAppWatchfaceMix.h index 5fa155475..bd89cc623 100644 --- a/include/apps/watchfaces/OswAppWatchfaceMix.h +++ b/include/apps/watchfaces/OswAppWatchfaceMix.h @@ -1,5 +1,4 @@ -#ifndef OSW_APP_WATCHFACE_MIX_H -#define OSW_APP_WATCHFACE_MIX_H +#pragma once #include #include @@ -23,5 +22,3 @@ class OswAppWatchfaceMix : public OswApp { void analogWatchDisplay(); //thin OswUI* ui; }; - -#endif From 07698d1420e918a48b53edbca0e132d1ea21497b Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Tue, 14 Jun 2022 16:44:18 +0900 Subject: [PATCH 024/116] OswAppWatchfaceMix : replace variable --- src/apps/watchfaces/OswAppWatchfaceMix.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/apps/watchfaces/OswAppWatchfaceMix.cpp b/src/apps/watchfaces/OswAppWatchfaceMix.cpp index cc8baaa2e..8189a7f7e 100644 --- a/src/apps/watchfaces/OswAppWatchfaceMix.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceMix.cpp @@ -46,7 +46,7 @@ void OswAppWatchfaceMix::dateDisplay() { hal->gfx()->setTextSize(1); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(120-OFF_SET_DATE_DIGITAL_WATCH_X_COORD, 75); + hal->gfx()->setTextCursor(DISP_W / 2 - OFF_SET_DATE_DIGITAL_WATCH_X_COORD, 75); { char weekday3[4]; @@ -67,7 +67,7 @@ void OswAppWatchfaceMix::dateDisplay() { hal->gfx()->setTextSize(2); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(120-OFF_SET_DATE_DIGITAL_WATCH_X_COORD, 90); + hal->gfx()->setTextCursor(DISP_W / 2 - OFF_SET_DATE_DIGITAL_WATCH_X_COORD, 90); // i really would want the date to be dynamic based on what's in the config, but the most efficient thing to do right // now is simply three if statements covering the 3 common conditions. @@ -86,7 +86,7 @@ void OswAppWatchfaceMix::digitalWatchDisplay() { hal->gfx()->setTextSize(3); hal->gfx()->setTextMiddleAligned(); hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(120-OFF_SET_DATE_DIGITAL_WATCH_X_COORD, 120); + hal->gfx()->setTextCursor(DISP_W / 2 - OFF_SET_DATE_DIGITAL_WATCH_X_COORD, DISP_H / 2); hal->getLocalTime(&hour, &minute, &second, &afterNoon); OswAppWatchfaceDigital::timeOutput(hour, minute, second,false); @@ -96,7 +96,7 @@ void OswAppWatchfaceMix::digitalWatchDisplay() { hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextBottomAligned(); hal->gfx()->setTextSize(3); - hal->gfx()->setTextCursor(120-OFF_SET_DATE_DIGITAL_WATCH_X_COORD + hal->gfx()->getTextOfsetColumns(5.25), 130); + hal->gfx()->setTextCursor(DISP_W / 2 - OFF_SET_DATE_DIGITAL_WATCH_X_COORD + hal->gfx()->getTextOfsetColumns(5.25), 130); hal->gfx()->setTextSize(1); hal->gfx()->print(" "); if (afterNoon) { From 85c0e6f8038d5f4762bbcb819797d1f0520179ab Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Tue, 14 Jun 2022 14:57:59 +0200 Subject: [PATCH 025/116] Minor path cleanup --- platformio.ini | 14 +++++++------- .../{build_install => build}/prebuild_cppflags.py | 0 scripts/{build_install => build}/prebuild_info.py | 0 scripts/{build_install => build}/prebuild_lua.py | 0 scripts/{build_install => build}/prebuild_www.py | 0 scripts/{build_install => }/install.py | 0 scripts/{update_sync => }/update.sh | 0 7 files changed, 7 insertions(+), 7 deletions(-) rename scripts/{build_install => build}/prebuild_cppflags.py (100%) rename scripts/{build_install => build}/prebuild_info.py (100%) rename scripts/{build_install => build}/prebuild_lua.py (100%) rename scripts/{build_install => build}/prebuild_www.py (100%) rename scripts/{build_install => }/install.py (100%) rename scripts/{update_sync => }/update.sh (100%) diff --git a/platformio.ini b/platformio.ini index b7d2a2b79..632d0105a 100755 --- a/platformio.ini +++ b/platformio.ini @@ -35,9 +35,9 @@ upload_speed = 460800 monitor_speed = 115200 ; Define additional build stage scripts - used to "compile" the html or define additional information extra_scripts = - pre:scripts/build_install/prebuild_info.py - pre:scripts/build_install/prebuild_www.py - pre:scripts/build_install/prebuild_cppflags.py + pre:scripts/build/prebuild_info.py + pre:scripts/build/prebuild_www.py + pre:scripts/build/prebuild_cppflags.py ; Light edition by hardware revisions [env:LIGHT_EDITION_V3_2] @@ -66,10 +66,10 @@ build_flags = -D OSW_FEATURE_WIFI -D LUA_C89_NUMBERS ; Required by OSW_FEATURE_LUA extra_scripts = - pre:scripts/build_install/prebuild_info.py - pre:scripts/build_install/prebuild_www.py - pre:scripts/build_install/prebuild_cppflags.py - pre:scripts/build_install/prebuild_lua.py ; Needed to generate the .cxx file(s) + pre:scripts/build/prebuild_info.py + pre:scripts/build/prebuild_www.py + pre:scripts/build/prebuild_cppflags.py + pre:scripts/build/prebuild_lua.py ; Needed to generate the .cxx file(s) build_type = debug ; GPS edition by hardware revisions diff --git a/scripts/build_install/prebuild_cppflags.py b/scripts/build/prebuild_cppflags.py similarity index 100% rename from scripts/build_install/prebuild_cppflags.py rename to scripts/build/prebuild_cppflags.py diff --git a/scripts/build_install/prebuild_info.py b/scripts/build/prebuild_info.py similarity index 100% rename from scripts/build_install/prebuild_info.py rename to scripts/build/prebuild_info.py diff --git a/scripts/build_install/prebuild_lua.py b/scripts/build/prebuild_lua.py similarity index 100% rename from scripts/build_install/prebuild_lua.py rename to scripts/build/prebuild_lua.py diff --git a/scripts/build_install/prebuild_www.py b/scripts/build/prebuild_www.py similarity index 100% rename from scripts/build_install/prebuild_www.py rename to scripts/build/prebuild_www.py diff --git a/scripts/build_install/install.py b/scripts/install.py similarity index 100% rename from scripts/build_install/install.py rename to scripts/install.py diff --git a/scripts/update_sync/update.sh b/scripts/update.sh similarity index 100% rename from scripts/update_sync/update.sh rename to scripts/update.sh From 54f951f148c7a60f0a051e25c5cf45178bdea840 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Tue, 14 Jun 2022 22:03:38 +0900 Subject: [PATCH 026/116] Readme : add spacing --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 742598526..8165e4b57 100644 --- a/Readme.md +++ b/Readme.md @@ -62,7 +62,7 @@ http:///api/screenserver The `fetchScreen.sh` downloads the raw image buffer from the running screen server, and converts the image to png. The `composeScreen.sh` creates the image with a surrounding smartwatch (light edition). -#### The fast way(recommended) +#### The fast way (recommended) Run the following inside the `open-smartwatch-os` directory: From ae4f3173ab4af68e8aac6c199ce745f395bfe9d6 Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Tue, 14 Jun 2022 16:28:08 +0200 Subject: [PATCH 027/116] Removed interfering code style specification --- .clang-format | 9 --------- 1 file changed, 9 deletions(-) delete mode 100755 .clang-format diff --git a/.clang-format b/.clang-format deleted file mode 100755 index 49c782e9c..000000000 --- a/.clang-format +++ /dev/null @@ -1,9 +0,0 @@ ---- -BasedOnStyle: Google -BreakBeforeBraces: Attach -ColumnLimit: '120' -SpacesInParentheses: 'false' -TabWidth: '4' -UseTab: Never - -... From 553448b5e8a58199717bd8d1c3b069e3ca363e05 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Wed, 15 Jun 2022 01:32:49 +0900 Subject: [PATCH 028/116] OswAppKcalStats : remove comment (copy) --- src/apps/tools/OswAppKcalStats.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/apps/tools/OswAppKcalStats.cpp b/src/apps/tools/OswAppKcalStats.cpp index 22a74ca63..9477bb71d 100644 --- a/src/apps/tools/OswAppKcalStats.cpp +++ b/src/apps/tools/OswAppKcalStats.cpp @@ -87,16 +87,16 @@ void OswAppKcalStats::showCurvedChart() { hal->gfx()->setTextCursor(DISP_W / 2 - 7, 185); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()) / 7 )); hal->gfx()->setTextCursor(DISP_W / 2 - 7, 195); - hal->gfx()->print(hal->environment->getStepsTotalWeek()/7); // total step counter + hal->gfx()->print(hal->environment->getStepsTotalWeek()/7); hal->gfx()->setTextCursor(DISP_W / 2 - 7, 205); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek())/7); // total step counter + hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek())/7); hal->gfx()->setTextLeftAligned(); hal->gfx()->setTextCursor(DISP_W / 2 + 7, 185); hal->gfx()->print(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(wDay))+String(" m")); hal->gfx()->setTextCursor(DISP_W / 2 + 7, 195); - hal->gfx()->print(hal->environment->getStepsOnDay(wDay) + String(" ") + String(LANG_KCAL_STEP)); // total step counter + hal->gfx()->print(hal->environment->getStepsOnDay(wDay) + String(" ") + String(LANG_KCAL_STEP)); hal->gfx()->setTextCursor(DISP_W / 2 + 7, 205); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDay(wDay))+String(" kcal")); // total step counter + hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDay(wDay))+String(" kcal")); } void OswAppKcalStats::setup() {} From 4892de5624c75e9a40cde777c2b369b44bf65a11 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Wed, 15 Jun 2022 01:33:31 +0900 Subject: [PATCH 029/116] OswAppStepStats : remove comment (copy) --- src/apps/tools/OswAppStepStats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index 882175030..bfd1d4bf6 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -19,7 +19,7 @@ void OswAppStepStats::drawChart() { hal->getLocalDate(&dayOfMonth, &weekDay); for (uint8_t index = 0; index < 7; index++) { - uint32_t weekDayStep = hal->environment->getStepsOnDay(index); // virtual step simulation + uint32_t weekDayStep = hal->environment->getStepsOnDay(index); uint16_t chartStickValue = ((float)(weekDayStep > goalValue ? goalValue : weekDayStep) / goalValue) * chartStickHeight; uint16_t barColor = OswConfigAllKeys::stepsPerDay.get() <= weekDayStep ? ui->getSuccessColor() : changeColor(ui->getSuccessColor(),2.85); From f295a20324294f36927173fe07e40c668199a6c5 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Wed, 15 Jun 2022 01:34:57 +0900 Subject: [PATCH 030/116] OswAppStepStats : remove comment --- src/apps/tools/OswAppStepStats.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index bfd1d4bf6..c3a52376d 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -25,7 +25,6 @@ void OswAppStepStats::drawChart() { uint16_t barColor = OswConfigAllKeys::stepsPerDay.get() <= weekDayStep ? ui->getSuccessColor() : changeColor(ui->getSuccessColor(),2.85); chartStickValue = chartStickValue < 2 ? 0 : chartStickValue; - // step bars if (index == weekDay) { hal->gfx()->drawThickTick(60 + index * interval, 147, 0, chartStickHeight, 0, 5, ui->getForegroundColor()); From b4e4b0793c63f9b318edb4bc951e6ba4af95c639 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Wed, 15 Jun 2022 01:52:02 +0900 Subject: [PATCH 031/116] OswAppWatchfaceDual : clean comment --- include/apps/watchfaces/OswAppWatchfaceDual.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/apps/watchfaces/OswAppWatchfaceDual.h b/include/apps/watchfaces/OswAppWatchfaceDual.h index 722d1433c..517d01273 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDual.h +++ b/include/apps/watchfaces/OswAppWatchfaceDual.h @@ -14,12 +14,11 @@ class OswAppWatchfaceDual : public OswApp { virtual void loop() override; virtual void stop() override; ~OswAppWatchfaceDual() {}; + //for dual-time - static void drawProgressBar(OswUI* ui,uint8_t cx, uint8_t cy, uint8_t jump, uint8_t length, uint8_t value,float angle, uint8_t radius, uint16_t color, uint8_t* goal=nullptr); void drawAnimSec(); private: OswUI* ui; - // Blank to make the 2 clocks easier to recognize }; \ No newline at end of file From fdf9098b3f8a14b6be022d355d019d544a9a7825 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Wed, 15 Jun 2022 13:27:47 +0900 Subject: [PATCH 032/116] Readme : update readme for typo --- Readme.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Readme.md b/Readme.md index 8165e4b57..e16159149 100644 --- a/Readme.md +++ b/Readme.md @@ -4,12 +4,12 @@ ## Prerequirements -* install [Platformio Core](https://docs.platformio.org/en/latest/core/installation.html) or [Platformio IDE](https://docs.platformio.org/en/latest/integration/ide/vscode.html#ide-vscode) (which installes Pio core automatically) +* install [Platformio Core](https://docs.platformio.org/en/latest/core/installation.html) or [Platformio IDE](https://docs.platformio.org/en/latest/integration/ide/vscode.html#ide-vscode) (which installs Pio core automatically) * **For improved LUA Script support, see env:pico32_LIGHT_EDITION_PREBUILD_LUA**: install [SWIG](http://www.swig.org/Doc4.0/SWIGDocumentation.html#Preface_installation) (also available in most package managers, e.g. `brew install swig`) * Then clone this repository ``` -git clone --recurse-submodules https://github.com/Open-Smartwatch/open-smartwatch-os.git +$ git clone --recurse-submodules https://github.com/Open-Smartwatch/open-smartwatch-os.git ``` ## build (Visual Studio Code) @@ -17,7 +17,7 @@ git clone --recurse-submodules https://github.com/Open-Smartwatch/open-smartwatc Open the cloned repo in VSCode ``` -code open-smartwatch-os +$ code open-smartwatch-os ``` and rename file `include/config.h.example` to `include/config.h` and adapt the values according to your requirements and press f5 to build it. @@ -27,13 +27,13 @@ and rename file `include/config.h.example` to `include/config.h` and adapt the v You can instead go to the repo folder with your terminal and run ``` -pio run -e pico32_LIGHT_EDITION -t upload +$ pio run -e pico32_LIGHT_EDITION -t upload ``` respectively ``` -pio run -e pico32_GPS_EDITION -t upload +$ pio run -e pico32_GPS_EDITION -t upload ``` depending on the watch model. From 205dbfe9c27a08560171965794812ded19716a2c Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Wed, 15 Jun 2022 13:34:35 +0900 Subject: [PATCH 033/116] Readme : update readme some fixed --- Readme.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Readme.md b/Readme.md index e16159149..4e3239329 100644 --- a/Readme.md +++ b/Readme.md @@ -4,7 +4,7 @@ ## Prerequirements -* install [Platformio Core](https://docs.platformio.org/en/latest/core/installation.html) or [Platformio IDE](https://docs.platformio.org/en/latest/integration/ide/vscode.html#ide-vscode) (which installs Pio core automatically) +* install [PlatformIO Core](https://docs.platformio.org/en/latest/core/installation.html) or [PlatformIO IDE](https://docs.platformio.org/en/latest/integration/ide/vscode.html#ide-vscode) (which installs PlatformIO core automatically) * **For improved LUA Script support, see env:pico32_LIGHT_EDITION_PREBUILD_LUA**: install [SWIG](http://www.swig.org/Doc4.0/SWIGDocumentation.html#Preface_installation) (also available in most package managers, e.g. `brew install swig`) * Then clone this repository @@ -14,13 +14,13 @@ $ git clone --recurse-submodules https://github.com/Open-Smartwatch/open-smartwa ## build (Visual Studio Code) -Open the cloned repo in VSCode +Open the cloned repo in VSCode: ``` $ code open-smartwatch-os ``` -and rename file `include/config.h.example` to `include/config.h` and adapt the values according to your requirements and press f5 to build it. +And rename file `include/config.h.example` to `include/config.h` and adapt the values according to your requirements and press `F5` to build it. ## build (CLI) @@ -36,14 +36,14 @@ respectively $ pio run -e pico32_GPS_EDITION -t upload ``` -depending on the watch model. +Depending on the watch model. ## Creating Screen Shots of your Apps -* Wifi needs to be able to connect for this to work. -* you will need bash and imagemagick for the helper scripts to work +* Wi-Fi needs to be able to connect for this to work. +* you will need bash and ImageMagick for the helper scripts to work The raw screenserver runs in the background and prints via serial: @@ -54,7 +54,7 @@ http:///api/screenserver ### HowTo - * add `-D RAW_SCREEN_SERVER` to your build flags in `platformio.ini`` + * add `-D RAW_SCREEN_SERVER` to your build flags in `platformio.ini` * build + flash + reset watch * wait for the server to be started (see msg above) * run `bash fetchScreen.sh screenshot.png` From 2045dc5ca6026d85ef368eb4afd6cb80eb56fdc4 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 15 Jun 2022 10:30:11 +0000 Subject: [PATCH 034/116] Applied formatting --- include/apps/watchfaces/OswAppWatchfaceDual.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/apps/watchfaces/OswAppWatchfaceDual.h b/include/apps/watchfaces/OswAppWatchfaceDual.h index 517d01273..a72edfc14 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDual.h +++ b/include/apps/watchfaces/OswAppWatchfaceDual.h @@ -14,7 +14,7 @@ class OswAppWatchfaceDual : public OswApp { virtual void loop() override; virtual void stop() override; ~OswAppWatchfaceDual() {}; - + //for dual-time static void drawProgressBar(OswUI* ui,uint8_t cx, uint8_t cy, uint8_t jump, uint8_t length, uint8_t value,float angle, uint8_t radius, uint16_t color, uint8_t* goal=nullptr); void drawAnimSec(); From 411d8419dea289cf2f773720f794b8b246de65b3 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sun, 12 Jun 2022 07:24:55 +0900 Subject: [PATCH 035/116] OSW-CONFIG : add fallback wifi with select Wi-FI --- include/osw_config_keys.h | 5 +++++ src/osw_config_keys.cpp | 14 +++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/osw_config_keys.h b/include/osw_config_keys.h index 89e795dab..0e84c7652 100644 --- a/include/osw_config_keys.h +++ b/include/osw_config_keys.h @@ -31,6 +31,11 @@ extern OswConfigKeyBool wifiAlwaysNTPEnabled; extern OswConfigKeyBool wifiAutoAP; extern OswConfigKeyString wifiSsid; extern OswConfigKeyPassword wifiPass; +extern OswConfigKeyString fallbackWifiSsid1st; +extern OswConfigKeyPassword fallbackWifiPass1st; +extern OswConfigKeyString fallbackWifiSsid2nd; +extern OswConfigKeyPassword fallbackWifiPass2nd; +extern OswConfigKeyDropDown settingWiFi; #endif extern OswConfigKeyRGB themeBackgroundColor; extern OswConfigKeyRGB themeBackgroundDimmedColor; diff --git a/src/osw_config_keys.cpp b/src/osw_config_keys.cpp index 58b8150fd..03bc9a53b 100644 --- a/src/osw_config_keys.cpp +++ b/src/osw_config_keys.cpp @@ -19,6 +19,11 @@ OswConfigKeyBool wifiAutoAP("l", "WiFi", "Enable Auto AP", "When the connection to the wifi fails, just create an own wifi station.", WIFI_AUTO_AP); OswConfigKeyString wifiSsid("a", "WiFi", "SSID", "Your wifi name", CONFIG_WIFI_SSID); OswConfigKeyPassword wifiPass("b", "WiFi", "Password", nullptr, CONFIG_WIFI_PASS); +OswConfigKeyString fallbackWifiSsid1st("a1", "WiFi", "Fallback 1st SSID", "Your fallback 1st wifi name", CONFIG_FALLBACK_1ST_WIFI_SSID); +OswConfigKeyPassword fallbackWifiPass1st("b1", "WiFi", "Password", nullptr, CONFIG_FALLBACK_1ST_WIFI_PASS); +OswConfigKeyString fallbackWifiSsid2nd("a2", "WiFi", "Fallback 2nd SSID", "Your fallback 2nd wifi name", CONFIG_FALLBACK_2ND_WIFI_SSID); +OswConfigKeyPassword fallbackWifiPass2nd("b2", "WiFi", "Password", nullptr, CONFIG_FALLBACK_2ND_WIFI_PASS); +OswConfigKeyDropDown settingWiFi("a0", "WiFi", "Select Wi-Fi.", "1,2,3", String(1)); #endif OswConfigKeyShort settingDisplayBrightness("s1", "Display", "Display Brightness", "From 0 to 255", @@ -81,17 +86,20 @@ OswConfigKey* oswConfigKeys[] = { #ifdef OSW_FEATURE_WIFI // wifi &OswConfigAllKeys::hostname, &OswConfigAllKeys::wifiSsid, &OswConfigAllKeys::wifiPass, + &OswConfigAllKeys::fallbackWifiSsid1st,&OswConfigAllKeys::fallbackWifiPass1st, + &OswConfigAllKeys::fallbackWifiSsid2nd,&OswConfigAllKeys::fallbackWifiPass2nd, + &OswConfigAllKeys::settingWiFi, #ifdef OSW_FEATURE_WIFI_ONBOOT - & OswConfigAllKeys::wifiBootEnabled, + &OswConfigAllKeys::wifiBootEnabled, #endif - & OswConfigAllKeys::wifiAlwaysNTPEnabled, &OswConfigAllKeys::wifiAutoAP, + &OswConfigAllKeys::wifiAlwaysNTPEnabled, &OswConfigAllKeys::wifiAutoAP, #endif // display &OswConfigAllKeys::settingDisplayTimeout, &OswConfigAllKeys::settingDisplayBrightness, &OswConfigAllKeys::settingDisplayOverlays, &OswConfigAllKeys::settingDisplayOverlaysOnWatchScreen, &OswConfigAllKeys::settingDisplayDefaultWatchface, &OswConfigAllKeys::settingDisplayDualHourTick, #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 - & OswConfigAllKeys::settingDisplayStepsGoal, + &OswConfigAllKeys::settingDisplayStepsGoal, #endif // energy &OswConfigAllKeys::buttonToWakeEnabled, &OswConfigAllKeys::raiseToWakeEnabled, From 2b8dbe1e445f7d75451dd9a7427cc0efe68d9784 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sat, 11 Jun 2022 19:39:37 +0900 Subject: [PATCH 036/116] Config : update fallback wifi config value -resolve #234 --- include/config.h.example | 4 ++++ include/config_defaults.h | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/config.h.example b/include/config.h.example index e10217e3e..ed77081f5 100644 --- a/include/config.h.example +++ b/include/config.h.example @@ -7,6 +7,10 @@ #define CONFIG_WIFI_SSID "yourSSID" #define CONFIG_WIFI_PASS "yourP4ssw0rd" +#define CONFIG_FALLBACK_1ST_WIFI_SSID CONFIG_WIFI_SSID +#define CONFIG_FALLBACK_1ST_WIFI_PASS CONFIG_WIFI_PASS +#define CONFIG_FALLBACK_2ND_WIFI_SSID CONFIG_WIFI_SSID +#define CONFIG_FALLBACK_2ND_WIFI_PASS CONFIG_WIFI_PASS #define LOCALE "locales/en-US.h" diff --git a/include/config_defaults.h b/include/config_defaults.h index 4a304c05a..74fa76806 100644 --- a/include/config_defaults.h +++ b/include/config_defaults.h @@ -71,6 +71,18 @@ #ifndef CONFIG_WIFI_PASS #define CONFIG_WIFI_PASS "P4ssw0rd!" #endif +#ifndef CONFIG_FALLBACK_1ST_WIFI_SSID +#define CONFIG_FALLBACK_1ST_WIFI_SSID CONFIG_WIFI_SSID +#endif +#ifndef CONFIG_FALLBACK_1ST_WIFI_PASS +#define CONFIG_FALLBACK_1ST_WIFI_PASS CONFIG_WIFI_PASS +#endif +#ifndef CONFIG_FALLBACK_1ST_WIFI_PASS +#define CONFIG_FALLBACK_2ND_WIFI_SSID CONFIG_WIFI_SSID +#endif +#ifndef CONFIG_FALLBACK_2ND_WIFI_PASS +#define CONFIG_FALLBACK_2ND_WIFI_PASS CONFIG_WIFI_PASS +#endif #ifndef DISPLAY_BRIGHTNESS // DISPLAY_MIN_BRIGHTNESS - 255 From 09190cea545931b344560c5f644797aa7997838a Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Sun, 12 Jun 2022 07:35:06 +0900 Subject: [PATCH 037/116] OswServiceTaskWiFi : select Wi-Fi --- src/services/OswServiceTaskWiFi.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/services/OswServiceTaskWiFi.cpp b/src/services/OswServiceTaskWiFi.cpp index 162dc1ad7..a6b41412e 100644 --- a/src/services/OswServiceTaskWiFi.cpp +++ b/src/services/OswServiceTaskWiFi.cpp @@ -179,15 +179,34 @@ bool OswServiceTaskWiFi::isWiFiEnabled() { void OswServiceTaskWiFi::connectWiFi() { this->m_hostname = std::move(OswConfigAllKeys::hostname.get()); this->m_autoAPTimeout = 0; //First reset to avoid racing conditions + + switch (OswConfigAllKeys::settingDisplayDefaultWatchface.get().toInt()) { + case 1: + this->m_clientSSID = std::move(OswConfigAllKeys::wifiSsid.get()); + this->m_clientPass = std::move(OswConfigAllKeys::wifiPass.get()); + break; + case 2: + this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid1st.get()); + this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass1st.get()); + break; + case 3: + this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid2nd.get()); + this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass2nd.get()); + break; + } this->m_clientSSID = std::move(OswConfigAllKeys::wifiSsid.get()); this->m_clientPass = std::move(OswConfigAllKeys::wifiPass.get()); this->m_enableClient = true; this->updateWiFiConfig(); - WiFi.begin(this->m_clientSSID.c_str(), this->m_clientPass.c_str()); + if (this->m_clientPass.c_str()) { // if Public Wi-Fi without a password + WiFi.begin(this->m_clientSSID.c_str(), this->m_clientPass.c_str()); + } else { + WiFi.begin(this->m_clientSSID.c_str()); + } if(!this->m_queuedNTPUpdate) this->m_queuedNTPUpdate = OswConfigAllKeys::wifiAlwaysNTPEnabled.get(); #ifndef NDEBUG - Serial.println(String(__FILE__) + ": [Client] Connecting to SSID " + OswConfigAllKeys::wifiSsid.get() + "..."); + Serial.println(String(__FILE__) + ": [Client] Connecting to SSID " + this->m_clientSSID + "..."); #endif } From c06079cc85613fb9d9c9ad89b500ae7991a0cedf Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Tue, 14 Jun 2022 03:50:46 +0900 Subject: [PATCH 038/116] Config : change default value --- include/config.h.example | 8 ++++---- include/config_defaults.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/config.h.example b/include/config.h.example index ed77081f5..4d88a8cca 100644 --- a/include/config.h.example +++ b/include/config.h.example @@ -7,10 +7,10 @@ #define CONFIG_WIFI_SSID "yourSSID" #define CONFIG_WIFI_PASS "yourP4ssw0rd" -#define CONFIG_FALLBACK_1ST_WIFI_SSID CONFIG_WIFI_SSID -#define CONFIG_FALLBACK_1ST_WIFI_PASS CONFIG_WIFI_PASS -#define CONFIG_FALLBACK_2ND_WIFI_SSID CONFIG_WIFI_SSID -#define CONFIG_FALLBACK_2ND_WIFI_PASS CONFIG_WIFI_PASS +#define CONFIG_FALLBACK_1ST_WIFI_SSID "" +#define CONFIG_FALLBACK_1ST_WIFI_PASS "" +#define CONFIG_FALLBACK_2ND_WIFI_SSID "" +#define CONFIG_FALLBACK_2ND_WIFI_PASS "" #define LOCALE "locales/en-US.h" diff --git a/include/config_defaults.h b/include/config_defaults.h index 74fa76806..b22a0d68c 100644 --- a/include/config_defaults.h +++ b/include/config_defaults.h @@ -72,16 +72,16 @@ #define CONFIG_WIFI_PASS "P4ssw0rd!" #endif #ifndef CONFIG_FALLBACK_1ST_WIFI_SSID -#define CONFIG_FALLBACK_1ST_WIFI_SSID CONFIG_WIFI_SSID +#define CONFIG_FALLBACK_1ST_WIFI_SSID "" #endif #ifndef CONFIG_FALLBACK_1ST_WIFI_PASS -#define CONFIG_FALLBACK_1ST_WIFI_PASS CONFIG_WIFI_PASS +#define CONFIG_FALLBACK_1ST_WIFI_PASS "" #endif #ifndef CONFIG_FALLBACK_1ST_WIFI_PASS -#define CONFIG_FALLBACK_2ND_WIFI_SSID CONFIG_WIFI_SSID +#define CONFIG_FALLBACK_2ND_WIFI_SSID "" #endif #ifndef CONFIG_FALLBACK_2ND_WIFI_PASS -#define CONFIG_FALLBACK_2ND_WIFI_PASS CONFIG_WIFI_PASS +#define CONFIG_FALLBACK_2ND_WIFI_PASS "" #endif #ifndef DISPLAY_BRIGHTNESS From ec11742c6c4b4d9f2c3e6f68d6b57cb721fc6c9d Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Tue, 14 Jun 2022 03:52:06 +0900 Subject: [PATCH 039/116] OSW-CONFIG : remove select Wi-Fi --- include/osw_config_keys.h | 1 - src/osw_config_keys.cpp | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/include/osw_config_keys.h b/include/osw_config_keys.h index 0e84c7652..748018c78 100644 --- a/include/osw_config_keys.h +++ b/include/osw_config_keys.h @@ -35,7 +35,6 @@ extern OswConfigKeyString fallbackWifiSsid1st; extern OswConfigKeyPassword fallbackWifiPass1st; extern OswConfigKeyString fallbackWifiSsid2nd; extern OswConfigKeyPassword fallbackWifiPass2nd; -extern OswConfigKeyDropDown settingWiFi; #endif extern OswConfigKeyRGB themeBackgroundColor; extern OswConfigKeyRGB themeBackgroundDimmedColor; diff --git a/src/osw_config_keys.cpp b/src/osw_config_keys.cpp index 03bc9a53b..945636f3a 100644 --- a/src/osw_config_keys.cpp +++ b/src/osw_config_keys.cpp @@ -19,11 +19,10 @@ OswConfigKeyBool wifiAutoAP("l", "WiFi", "Enable Auto AP", "When the connection to the wifi fails, just create an own wifi station.", WIFI_AUTO_AP); OswConfigKeyString wifiSsid("a", "WiFi", "SSID", "Your wifi name", CONFIG_WIFI_SSID); OswConfigKeyPassword wifiPass("b", "WiFi", "Password", nullptr, CONFIG_WIFI_PASS); -OswConfigKeyString fallbackWifiSsid1st("a1", "WiFi", "Fallback 1st SSID", "Your fallback 1st wifi name", CONFIG_FALLBACK_1ST_WIFI_SSID); -OswConfigKeyPassword fallbackWifiPass1st("b1", "WiFi", "Password", nullptr, CONFIG_FALLBACK_1ST_WIFI_PASS); -OswConfigKeyString fallbackWifiSsid2nd("a2", "WiFi", "Fallback 2nd SSID", "Your fallback 2nd wifi name", CONFIG_FALLBACK_2ND_WIFI_SSID); -OswConfigKeyPassword fallbackWifiPass2nd("b2", "WiFi", "Password", nullptr, CONFIG_FALLBACK_2ND_WIFI_PASS); -OswConfigKeyDropDown settingWiFi("a0", "WiFi", "Select Wi-Fi.", "1,2,3", String(1)); +OswConfigKeyString fallbackWifiSsid1st("a1", "WiFi", "Fallback 1st SSID", "Your fallback 1st wifi name", String(CONFIG_FALLBACK_1ST_WIFI_SSID)); +OswConfigKeyPassword fallbackWifiPass1st("b1", "WiFi", "Password", nullptr, String(CONFIG_FALLBACK_1ST_WIFI_PASS)); +OswConfigKeyString fallbackWifiSsid2nd("a2", "WiFi", "Fallback 2nd SSID", "Your fallback 2nd wifi name", String(CONFIG_FALLBACK_2ND_WIFI_SSID)); +OswConfigKeyPassword fallbackWifiPass2nd("b2", "WiFi", "Password", nullptr, String(CONFIG_FALLBACK_2ND_WIFI_PASS)); #endif OswConfigKeyShort settingDisplayBrightness("s1", "Display", "Display Brightness", "From 0 to 255", @@ -88,7 +87,6 @@ OswConfigKey* oswConfigKeys[] = { &OswConfigAllKeys::hostname, &OswConfigAllKeys::wifiSsid, &OswConfigAllKeys::wifiPass, &OswConfigAllKeys::fallbackWifiSsid1st,&OswConfigAllKeys::fallbackWifiPass1st, &OswConfigAllKeys::fallbackWifiSsid2nd,&OswConfigAllKeys::fallbackWifiPass2nd, - &OswConfigAllKeys::settingWiFi, #ifdef OSW_FEATURE_WIFI_ONBOOT &OswConfigAllKeys::wifiBootEnabled, #endif From 235fb3645f7abca5c4446aaf7d73ea6966b04133 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Tue, 14 Jun 2022 03:55:45 +0900 Subject: [PATCH 040/116] OswServiceTaskWiFi : adding a WiFi connection count counter --- include/services/OswServiceTaskWiFi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/services/OswServiceTaskWiFi.h b/include/services/OswServiceTaskWiFi.h index 14dbef75f..9eea9498e 100644 --- a/include/services/OswServiceTaskWiFi.h +++ b/include/services/OswServiceTaskWiFi.h @@ -66,7 +66,7 @@ class OswServiceTaskWiFi : public OswServiceTask { String m_clientSSID; String m_clientPass; String m_stationPass; - + uint8_t count = 1; void updateWiFiConfig(); }; From b56cc8c30c191b697f2bb4ed6cf71f38d2094a7f Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Tue, 14 Jun 2022 03:58:46 +0900 Subject: [PATCH 041/116] OswServiceTaskWiFi : connect Wi-Fi count counter and use public network --- src/services/OswServiceTaskWiFi.cpp | 52 +++++++++++++++++------------ 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/src/services/OswServiceTaskWiFi.cpp b/src/services/OswServiceTaskWiFi.cpp index a6b41412e..ac348cd3e 100644 --- a/src/services/OswServiceTaskWiFi.cpp +++ b/src/services/OswServiceTaskWiFi.cpp @@ -54,12 +54,18 @@ void OswServiceTaskWiFi::loop() { } if(OswConfigAllKeys::wifiAutoAP.get() && !this->m_enableStation and this->m_autoAPTimeout and this->m_autoAPTimeout < time(nullptr) - 10) { //10 seconds no network -> auto ap! - this->enableStation(); - this->m_enabledStationByAutoAP = time(nullptr); + if(count<=3){ + this->connectWiFi(); + count+=1; + } else { + count = 1; + this->enableStation(); + this->m_enabledStationByAutoAP = time(nullptr); #ifndef NDEBUG - Serial.println(String(__FILE__) + ": [AutoAP] Active for " + String(this->m_enabledStationByAutoAPTimeout) + " seconds (password is " + this->m_stationPass + ")."); + Serial.println(String(__FILE__) + ": [AutoAP] Active for " + String(this->m_enabledStationByAutoAPTimeout) + " seconds (password is " + this->m_stationPass + ")."); #endif - } + } + } if(this->m_queuedNTPUpdate and WiFi.status() == WL_CONNECTED) { OswHal::getInstance()->devices->esp32->triggerNTPUpdate(); @@ -180,28 +186,30 @@ void OswServiceTaskWiFi::connectWiFi() { this->m_hostname = std::move(OswConfigAllKeys::hostname.get()); this->m_autoAPTimeout = 0; //First reset to avoid racing conditions - switch (OswConfigAllKeys::settingDisplayDefaultWatchface.get().toInt()) { - case 1: - this->m_clientSSID = std::move(OswConfigAllKeys::wifiSsid.get()); - this->m_clientPass = std::move(OswConfigAllKeys::wifiPass.get()); - break; - case 2: - this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid1st.get()); - this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass1st.get()); - break; - case 3: - this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid2nd.get()); - this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass2nd.get()); - break; + switch (count) { + case 1: + this->m_clientSSID = std::move(OswConfigAllKeys::wifiSsid.get()); + this->m_clientPass = std::move(OswConfigAllKeys::wifiPass.get()); + break; + if(!OswConfigAllKeys::fallbackWifiSsid1st.get().isEmpty()){ + case 2: + this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid1st.get()); + this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass1st.get()); + break; + } + if (!OswConfigAllKeys::fallbackWifiSsid2nd.get().isEmpty()) { + case 3: + this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid2nd.get()); + this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass2nd.get()); + break; + } } - this->m_clientSSID = std::move(OswConfigAllKeys::wifiSsid.get()); - this->m_clientPass = std::move(OswConfigAllKeys::wifiPass.get()); this->m_enableClient = true; this->updateWiFiConfig(); - if (this->m_clientPass.c_str()) { // if Public Wi-Fi without a password - WiFi.begin(this->m_clientSSID.c_str(), this->m_clientPass.c_str()); - } else { + if (this->m_clientPass.isEmpty()) { // if Public Wi-Fi without a password WiFi.begin(this->m_clientSSID.c_str()); + } else { + WiFi.begin(this->m_clientSSID.c_str(), this->m_clientPass.c_str()); } if(!this->m_queuedNTPUpdate) this->m_queuedNTPUpdate = OswConfigAllKeys::wifiAlwaysNTPEnabled.get(); From b0d13314a5b92d1f5ce7c2aad5830ea83b893bff Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Tue, 14 Jun 2022 07:55:02 +0900 Subject: [PATCH 042/116] OswServiceTaskWiFi : rename param and add loadCredentials() --- include/services/OswServiceTaskWiFi.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/services/OswServiceTaskWiFi.h b/include/services/OswServiceTaskWiFi.h index 9eea9498e..cf7ccea9e 100644 --- a/include/services/OswServiceTaskWiFi.h +++ b/include/services/OswServiceTaskWiFi.h @@ -31,6 +31,7 @@ class OswServiceTaskWiFi : public OswServiceTask { //WiFi (client) bool isWiFiEnabled(); void connectWiFi(); + void loadCredentials(uint8_t reconnectCount); void disconnectWiFi(); IPAddress getClientIP(); @@ -66,7 +67,7 @@ class OswServiceTaskWiFi : public OswServiceTask { String m_clientSSID; String m_clientPass; String m_stationPass; - uint8_t count = 1; + uint8_t reconnectCount = 1; // reconnect try number of SSID void updateWiFiConfig(); }; From acaccd2f5af5d5369ec0b74970da0a4845d6c983 Mon Sep 17 00:00:00 2001 From: Ruffalo-sunghwan Date: Tue, 14 Jun 2022 07:59:33 +0900 Subject: [PATCH 043/116] OswServiceTaskWiFi : rename param and extract to function --- src/services/OswServiceTaskWiFi.cpp | 46 +++++++++++++++-------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/services/OswServiceTaskWiFi.cpp b/src/services/OswServiceTaskWiFi.cpp index ac348cd3e..7da0da59d 100644 --- a/src/services/OswServiceTaskWiFi.cpp +++ b/src/services/OswServiceTaskWiFi.cpp @@ -54,11 +54,11 @@ void OswServiceTaskWiFi::loop() { } if(OswConfigAllKeys::wifiAutoAP.get() && !this->m_enableStation and this->m_autoAPTimeout and this->m_autoAPTimeout < time(nullptr) - 10) { //10 seconds no network -> auto ap! - if(count<=3){ + if(reconnectCount<3){ + reconnectCount+=1; this->connectWiFi(); - count+=1; } else { - count = 1; + reconnectCount = 1; this->enableStation(); this->m_enabledStationByAutoAP = time(nullptr); #ifndef NDEBUG @@ -179,31 +179,33 @@ bool OswServiceTaskWiFi::isWiFiEnabled() { return this->m_enableClient; } +void OswServiceTaskWiFi::loadCredentials(uint8_t reconnectCount) { + switch (reconnectCount) { + case 1: + this->m_clientSSID = std::move(OswConfigAllKeys::wifiSsid.get()); + this->m_clientPass = std::move(OswConfigAllKeys::wifiPass.get()); + break; + if (!OswConfigAllKeys::fallbackWifiSsid1st.get().isEmpty()) { + case 2: + this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid1st.get()); + this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass1st.get()); + break; + } + if (!OswConfigAllKeys::fallbackWifiSsid2nd.get().isEmpty()) { + case 3: + this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid2nd.get()); + this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass2nd.get()); + break; + } + } +} /** * Connect to the wifi, using the provided credentials from the config... */ void OswServiceTaskWiFi::connectWiFi() { this->m_hostname = std::move(OswConfigAllKeys::hostname.get()); this->m_autoAPTimeout = 0; //First reset to avoid racing conditions - - switch (count) { - case 1: - this->m_clientSSID = std::move(OswConfigAllKeys::wifiSsid.get()); - this->m_clientPass = std::move(OswConfigAllKeys::wifiPass.get()); - break; - if(!OswConfigAllKeys::fallbackWifiSsid1st.get().isEmpty()){ - case 2: - this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid1st.get()); - this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass1st.get()); - break; - } - if (!OswConfigAllKeys::fallbackWifiSsid2nd.get().isEmpty()) { - case 3: - this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid2nd.get()); - this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass2nd.get()); - break; - } - } + loadCredentials(this->reconnectCount); this->m_enableClient = true; this->updateWiFiConfig(); if (this->m_clientPass.isEmpty()) { // if Public Wi-Fi without a password From 1be15b4d7bfdf8ba0ee16feb4a2a77937e90380f Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Tue, 14 Jun 2022 15:19:11 +0200 Subject: [PATCH 044/116] Fixed compile error (copy-pasta) --- include/config_defaults.h | 2 +- src/osw_config_keys.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/config_defaults.h b/include/config_defaults.h index b22a0d68c..dc9dfff12 100644 --- a/include/config_defaults.h +++ b/include/config_defaults.h @@ -77,7 +77,7 @@ #ifndef CONFIG_FALLBACK_1ST_WIFI_PASS #define CONFIG_FALLBACK_1ST_WIFI_PASS "" #endif -#ifndef CONFIG_FALLBACK_1ST_WIFI_PASS +#ifndef CONFIG_FALLBACK_2ND_WIFI_SSID #define CONFIG_FALLBACK_2ND_WIFI_SSID "" #endif #ifndef CONFIG_FALLBACK_2ND_WIFI_PASS diff --git a/src/osw_config_keys.cpp b/src/osw_config_keys.cpp index 945636f3a..e1cf853eb 100644 --- a/src/osw_config_keys.cpp +++ b/src/osw_config_keys.cpp @@ -19,9 +19,9 @@ OswConfigKeyBool wifiAutoAP("l", "WiFi", "Enable Auto AP", "When the connection to the wifi fails, just create an own wifi station.", WIFI_AUTO_AP); OswConfigKeyString wifiSsid("a", "WiFi", "SSID", "Your wifi name", CONFIG_WIFI_SSID); OswConfigKeyPassword wifiPass("b", "WiFi", "Password", nullptr, CONFIG_WIFI_PASS); -OswConfigKeyString fallbackWifiSsid1st("a1", "WiFi", "Fallback 1st SSID", "Your fallback 1st wifi name", String(CONFIG_FALLBACK_1ST_WIFI_SSID)); +OswConfigKeyString fallbackWifiSsid1st("a1", "WiFi", "Fallback 1st SSID", "Your fallback 1st wifi name", CONFIG_FALLBACK_1ST_WIFI_SSID); OswConfigKeyPassword fallbackWifiPass1st("b1", "WiFi", "Password", nullptr, String(CONFIG_FALLBACK_1ST_WIFI_PASS)); -OswConfigKeyString fallbackWifiSsid2nd("a2", "WiFi", "Fallback 2nd SSID", "Your fallback 2nd wifi name", String(CONFIG_FALLBACK_2ND_WIFI_SSID)); +OswConfigKeyString fallbackWifiSsid2nd("a2", "WiFi", "Fallback 2nd SSID", "Your fallback 2nd wifi name", CONFIG_FALLBACK_2ND_WIFI_SSID); OswConfigKeyPassword fallbackWifiPass2nd("b2", "WiFi", "Password", nullptr, String(CONFIG_FALLBACK_2ND_WIFI_PASS)); #endif From 1bf743f4bb98220df3d273a78c7952f1000b47f6 Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Tue, 14 Jun 2022 15:32:28 +0200 Subject: [PATCH 045/116] Corrected wrong use of std::move() --- src/services/OswServiceTaskWiFi.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/services/OswServiceTaskWiFi.cpp b/src/services/OswServiceTaskWiFi.cpp index 7da0da59d..1ef8349d0 100644 --- a/src/services/OswServiceTaskWiFi.cpp +++ b/src/services/OswServiceTaskWiFi.cpp @@ -182,19 +182,19 @@ bool OswServiceTaskWiFi::isWiFiEnabled() { void OswServiceTaskWiFi::loadCredentials(uint8_t reconnectCount) { switch (reconnectCount) { case 1: - this->m_clientSSID = std::move(OswConfigAllKeys::wifiSsid.get()); - this->m_clientPass = std::move(OswConfigAllKeys::wifiPass.get()); + this->m_clientSSID = OswConfigAllKeys::wifiSsid.get(); + this->m_clientPass = OswConfigAllKeys::wifiPass.get(); break; if (!OswConfigAllKeys::fallbackWifiSsid1st.get().isEmpty()) { case 2: - this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid1st.get()); - this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass1st.get()); + this->m_clientSSID = OswConfigAllKeys::fallbackWifiSsid1st.get(); + this->m_clientPass = OswConfigAllKeys::fallbackWifiPass1st.get(); break; } if (!OswConfigAllKeys::fallbackWifiSsid2nd.get().isEmpty()) { case 3: - this->m_clientSSID = std::move(OswConfigAllKeys::fallbackWifiSsid2nd.get()); - this->m_clientPass = std::move(OswConfigAllKeys::fallbackWifiPass2nd.get()); + this->m_clientSSID = OswConfigAllKeys::fallbackWifiSsid2nd.get(); + this->m_clientPass = OswConfigAllKeys::fallbackWifiPass2nd.get(); break; } } @@ -203,7 +203,7 @@ void OswServiceTaskWiFi::loadCredentials(uint8_t reconnectCount) { * Connect to the wifi, using the provided credentials from the config... */ void OswServiceTaskWiFi::connectWiFi() { - this->m_hostname = std::move(OswConfigAllKeys::hostname.get()); + this->m_hostname = OswConfigAllKeys::hostname.get(); this->m_autoAPTimeout = 0; //First reset to avoid racing conditions loadCredentials(this->reconnectCount); this->m_enableClient = true; @@ -243,7 +243,7 @@ bool OswServiceTaskWiFi::isStationEnabled() { * @param password Set the wifi password to this (at least 8 chars!), otherwise a random password will be choosen. */ void OswServiceTaskWiFi::enableStation(const String& password) { - this->m_hostname = std::move(OswConfigAllKeys::hostname.get()); + this->m_hostname = OswConfigAllKeys::hostname.get(); if(password.isEmpty()) //Generate password this->m_stationPass = String(random(10000000, 99999999)); //Generate random 8 chars long numeric password From edec00fe08ecc399214e97d42ad0f490e9bfe24c Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Tue, 14 Jun 2022 15:48:11 +0200 Subject: [PATCH 046/116] Fixed too small stack size for new config keys --- include/services/OswServiceManager.h | 4 ++-- src/osw_config.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/services/OswServiceManager.h b/include/services/OswServiceManager.h index 21465d0d3..b7916fb44 100644 --- a/include/services/OswServiceManager.h +++ b/include/services/OswServiceManager.h @@ -10,7 +10,7 @@ class OswServiceManager { return instance; } // + wifi service needs 1024 - // + webserver another 1024 + // + webserver another 4096 // + updater another 1024 //Temp workaround until #137 is done @@ -19,7 +19,7 @@ class OswServiceManager { #else #define _SERVICE_WIFI 0 #endif - const unsigned workerStackSize = 1024 + ((1024 + 1024 + 1024) * _SERVICE_WIFI); + const unsigned workerStackSize = 1024 + ((1024 + 4096 + 1024) * _SERVICE_WIFI); void setup(); void loop(); diff --git a/src/osw_config.cpp b/src/osw_config.cpp index 4a32c2f9f..7b0332be4 100644 --- a/src/osw_config.cpp +++ b/src/osw_config.cpp @@ -86,7 +86,7 @@ void OswConfig::reset() { OswConfig::~OswConfig() {}; String OswConfig::getConfigJSON() { - DynamicJsonDocument config(6144); //If you suddenly start missing keys, try increasing this... + DynamicJsonDocument config(8192); //If you suddenly start missing keys, try increasing this... /* * !!!NOTE!!! * @@ -122,7 +122,7 @@ void OswConfig::parseDataJSON(const char* json) { * names. */ - DynamicJsonDocument config(6144); + DynamicJsonDocument config(8192); deserializeJson(config, json); JsonArray entries = config["entries"].as(); From 1fec4d9da2d01d2a903029da87e367193b3748e0 Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Tue, 14 Jun 2022 16:05:55 +0200 Subject: [PATCH 047/116] Fixed webserver dynamic heap size limits --- include/services/OswServiceManager.h | 4 ++-- src/osw_config.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/services/OswServiceManager.h b/include/services/OswServiceManager.h index b7916fb44..7ec329e47 100644 --- a/include/services/OswServiceManager.h +++ b/include/services/OswServiceManager.h @@ -10,7 +10,7 @@ class OswServiceManager { return instance; } // + wifi service needs 1024 - // + webserver another 4096 + // + webserver another 2048 // + updater another 1024 //Temp workaround until #137 is done @@ -19,7 +19,7 @@ class OswServiceManager { #else #define _SERVICE_WIFI 0 #endif - const unsigned workerStackSize = 1024 + ((1024 + 4096 + 1024) * _SERVICE_WIFI); + const unsigned workerStackSize = 1024 + ((1024 + 2048 + 1024) * _SERVICE_WIFI); void setup(); void loop(); diff --git a/src/osw_config.cpp b/src/osw_config.cpp index 7b0332be4..e217c33c3 100644 --- a/src/osw_config.cpp +++ b/src/osw_config.cpp @@ -86,7 +86,7 @@ void OswConfig::reset() { OswConfig::~OswConfig() {}; String OswConfig::getConfigJSON() { - DynamicJsonDocument config(8192); //If you suddenly start missing keys, try increasing this... + DynamicJsonDocument config(16384); //If you suddenly start missing keys, try increasing this... /* * !!!NOTE!!! * @@ -122,7 +122,7 @@ void OswConfig::parseDataJSON(const char* json) { * names. */ - DynamicJsonDocument config(8192); + DynamicJsonDocument config(16384); deserializeJson(config, json); JsonArray entries = config["entries"].as(); From 6cace8af09af5a6b62c8080b5a448fe3e85b79c5 Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Tue, 14 Jun 2022 16:06:17 +0200 Subject: [PATCH 048/116] Renamed key names --- src/osw_config_keys.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/osw_config_keys.cpp b/src/osw_config_keys.cpp index e1cf853eb..60d5d09b7 100644 --- a/src/osw_config_keys.cpp +++ b/src/osw_config_keys.cpp @@ -17,12 +17,12 @@ OswConfigKeyBool wifiBootEnabled("j", "WiFi", "Enable on boot", "This will drain OswConfigKeyBool wifiAlwaysNTPEnabled("k", "WiFi", "Always fetch time (when connected)", nullptr, NTP_ALWAYS_ON_WIFI); OswConfigKeyBool wifiAutoAP("l", "WiFi", "Enable Auto AP", "When the connection to the wifi fails, just create an own wifi station.", WIFI_AUTO_AP); -OswConfigKeyString wifiSsid("a", "WiFi", "SSID", "Your wifi name", CONFIG_WIFI_SSID); +OswConfigKeyString wifiSsid("a", "WiFi", "1st SSID", "Your wifi name", CONFIG_WIFI_SSID); OswConfigKeyPassword wifiPass("b", "WiFi", "Password", nullptr, CONFIG_WIFI_PASS); -OswConfigKeyString fallbackWifiSsid1st("a1", "WiFi", "Fallback 1st SSID", "Your fallback 1st wifi name", CONFIG_FALLBACK_1ST_WIFI_SSID); -OswConfigKeyPassword fallbackWifiPass1st("b1", "WiFi", "Password", nullptr, String(CONFIG_FALLBACK_1ST_WIFI_PASS)); -OswConfigKeyString fallbackWifiSsid2nd("a2", "WiFi", "Fallback 2nd SSID", "Your fallback 2nd wifi name", CONFIG_FALLBACK_2ND_WIFI_SSID); -OswConfigKeyPassword fallbackWifiPass2nd("b2", "WiFi", "Password", nullptr, String(CONFIG_FALLBACK_2ND_WIFI_PASS)); +OswConfigKeyString fallbackWifiSsid1st("a1", "WiFi", "2nd SSID", "Leave empty to disable", CONFIG_FALLBACK_1ST_WIFI_SSID); +OswConfigKeyPassword fallbackWifiPass1st("b1", "WiFi", "Password", nullptr, CONFIG_FALLBACK_1ST_WIFI_PASS); +OswConfigKeyString fallbackWifiSsid2nd("a2", "WiFi", "3rd SSID", "Leave empty to disable", CONFIG_FALLBACK_2ND_WIFI_SSID); +OswConfigKeyPassword fallbackWifiPass2nd("b2", "WiFi", "Password", nullptr, CONFIG_FALLBACK_2ND_WIFI_PASS); #endif OswConfigKeyShort settingDisplayBrightness("s1", "Display", "Display Brightness", "From 0 to 255", From dbece6e405b61c24f0cb9a225bbc393e03ef921b Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Tue, 14 Jun 2022 16:19:29 +0200 Subject: [PATCH 049/116] Fixed broken credentials selection --- src/services/OswServiceTaskWiFi.cpp | 39 +++++++++++++---------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/src/services/OswServiceTaskWiFi.cpp b/src/services/OswServiceTaskWiFi.cpp index 1ef8349d0..deff8efb7 100644 --- a/src/services/OswServiceTaskWiFi.cpp +++ b/src/services/OswServiceTaskWiFi.cpp @@ -54,11 +54,11 @@ void OswServiceTaskWiFi::loop() { } if(OswConfigAllKeys::wifiAutoAP.get() && !this->m_enableStation and this->m_autoAPTimeout and this->m_autoAPTimeout < time(nullptr) - 10) { //10 seconds no network -> auto ap! - if(reconnectCount<3){ - reconnectCount+=1; + if(this->reconnectCount < 3){ + ++this->reconnectCount; this->connectWiFi(); } else { - reconnectCount = 1; + this->reconnectCount = 1; this->enableStation(); this->m_enabledStationByAutoAP = time(nullptr); #ifndef NDEBUG @@ -180,24 +180,19 @@ bool OswServiceTaskWiFi::isWiFiEnabled() { } void OswServiceTaskWiFi::loadCredentials(uint8_t reconnectCount) { - switch (reconnectCount) { - case 1: - this->m_clientSSID = OswConfigAllKeys::wifiSsid.get(); - this->m_clientPass = OswConfigAllKeys::wifiPass.get(); - break; - if (!OswConfigAllKeys::fallbackWifiSsid1st.get().isEmpty()) { - case 2: - this->m_clientSSID = OswConfigAllKeys::fallbackWifiSsid1st.get(); - this->m_clientPass = OswConfigAllKeys::fallbackWifiPass1st.get(); - break; - } - if (!OswConfigAllKeys::fallbackWifiSsid2nd.get().isEmpty()) { - case 3: - this->m_clientSSID = OswConfigAllKeys::fallbackWifiSsid2nd.get(); - this->m_clientPass = OswConfigAllKeys::fallbackWifiPass2nd.get(); - break; - } - } + if(reconnectCount == 1) { + this->m_clientSSID = OswConfigAllKeys::wifiSsid.get(); + this->m_clientPass = OswConfigAllKeys::wifiPass.get(); + } else if(reconnectCount == 2 and !OswConfigAllKeys::fallbackWifiSsid1st.get().isEmpty()) { + this->m_clientSSID = OswConfigAllKeys::fallbackWifiSsid1st.get(); + this->m_clientPass = OswConfigAllKeys::fallbackWifiPass1st.get(); + } else if(reconnectCount == 3 and !OswConfigAllKeys::fallbackWifiSsid2nd.get().isEmpty()) { + this->m_clientSSID = OswConfigAllKeys::fallbackWifiSsid2nd.get(); + this->m_clientPass = OswConfigAllKeys::fallbackWifiPass2nd.get(); + } else { + // Shit. This should never heppen, as we should already be in station mode (or give up)... + Serial.println(String(__FILE__) + ": [Credentials] Failed to retreive the credentials for the " + reconnectCount + ". attempt?!"); + } } /** * Connect to the wifi, using the provided credentials from the config... @@ -205,7 +200,7 @@ void OswServiceTaskWiFi::loadCredentials(uint8_t reconnectCount) { void OswServiceTaskWiFi::connectWiFi() { this->m_hostname = OswConfigAllKeys::hostname.get(); this->m_autoAPTimeout = 0; //First reset to avoid racing conditions - loadCredentials(this->reconnectCount); + this->loadCredentials(this->reconnectCount); this->m_enableClient = true; this->updateWiFiConfig(); if (this->m_clientPass.isEmpty()) { // if Public Wi-Fi without a password From 579a5188c8d8aee4390d48e0a1f8983bfd36d00b Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Thu, 16 Jun 2022 12:40:12 +0200 Subject: [PATCH 050/116] Added current (PS)RAM information --- src/apps/tools/print_debug.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/apps/tools/print_debug.cpp b/src/apps/tools/print_debug.cpp index 2f53e51dd..a55a237d5 100644 --- a/src/apps/tools/print_debug.cpp +++ b/src/apps/tools/print_debug.cpp @@ -38,10 +38,11 @@ void OswAppPrintDebug::loop() { #endif y = 32; - printStatus("compiled", (String(__DATE__) + " " + String(__TIME__)).c_str()); + printStatus("Compiled", (String(__DATE__) + " " + String(__TIME__)).c_str()); + printStatus("RAM", (String(ESP.getHeapSize() - ESP.getFreeHeap()) + "B / " + ESP.getHeapSize() + "B").c_str()); #ifdef BOARD_HAS_PSRAM - printStatus("PSRAM", String(ESP.getPsramSize(), 10).c_str()); + printStatus("PSRAM", (String(ESP.getPsramSize() - ESP.getFreePsram()) + "B / " + String(ESP.getPsramSize()) + "B").c_str()); #endif #if OSW_PLATFORM_ENVIRONMENT == 1 #if OSW_PLATFORM_ENVIRONMENT_TEMPERATURE == 1 From 6a53ba0897bb8cef19f55acef6386b7f6a4ffac2 Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Thu, 16 Jun 2022 12:41:42 +0200 Subject: [PATCH 051/116] Corrected and finished ap selection code --- include/services/OswServiceTaskWiFi.h | 6 +- src/services/OswServiceTaskWiFi.cpp | 116 ++++++++++++++++---------- 2 files changed, 77 insertions(+), 45 deletions(-) diff --git a/include/services/OswServiceTaskWiFi.h b/include/services/OswServiceTaskWiFi.h index cf7ccea9e..d3ee3e16f 100644 --- a/include/services/OswServiceTaskWiFi.h +++ b/include/services/OswServiceTaskWiFi.h @@ -31,7 +31,6 @@ class OswServiceTaskWiFi : public OswServiceTask { //WiFi (client) bool isWiFiEnabled(); void connectWiFi(); - void loadCredentials(uint8_t reconnectCount); void disconnectWiFi(); IPAddress getClientIP(); @@ -62,13 +61,14 @@ class OswServiceTaskWiFi : public OswServiceTask { const time_t m_enabledStationByAutoAPTimeout = 10 * 60; // Maximum allowed time for the auto ap to stay active - after that it ALLWAYS WILL TRY to reconnect bool m_queuedNTPUpdate = false; //Will be set to true it this feature is active bool m_waitingForNTPUpdate = false; - time_t m_autoAPTimeout = 0; String m_hostname; String m_clientSSID; String m_clientPass; String m_stationPass; - uint8_t reconnectCount = 1; // reconnect try number of SSID + time_t m_connectTimeout = 0; + uint8_t m_connectFailureCount = 0; void updateWiFiConfig(); + void selectCredentials(); }; #endif diff --git a/src/services/OswServiceTaskWiFi.cpp b/src/services/OswServiceTaskWiFi.cpp index deff8efb7..16f119676 100644 --- a/src/services/OswServiceTaskWiFi.cpp +++ b/src/services/OswServiceTaskWiFi.cpp @@ -42,30 +42,54 @@ void OswServiceTaskWiFi::loop() { } if(this->m_enableClient) { - if(this->m_autoAPTimeout and WiFi.status() == WL_CONNECTED) { - //Nice - reset timeout - this->m_autoAPTimeout = 0; - } else if(!this->m_autoAPTimeout and WiFi.status() != WL_CONNECTED) { - //Wifi is either disconnected or unavailable -> start timeout until we start our own ap - this->m_autoAPTimeout = time(nullptr); + if(this->m_connectTimeout and WiFi.status() == WL_CONNECTED) { + // Nice - reset timeout + this->m_connectTimeout = 0; + this->m_connectFailureCount = 0; + } else if(!this->m_connectTimeout and WiFi.status() != WL_CONNECTED) { + // Wifi is either disconnected or unavailable... + if(this->onlyOneModeSimultaneously and this->m_enableStation) { + // This watch does not support connecting to networks with an active AutoAP. + // It would therefore be not helpful to activate the timeout to try an other + // action, while the AutoAP is active as this will shutdown the AutoAP as the + // timeout expires! + } else { + // -> start timeout + this->m_connectTimeout = time(nullptr); #ifndef NDEBUG - Serial.println(String(__FILE__) + ": [AutoAP] Timeout activated: 10 seconds"); + Serial.println(String(__FILE__) + ": [Connection] Timeout activated: 10 seconds"); #endif + } } - if(OswConfigAllKeys::wifiAutoAP.get() && !this->m_enableStation and this->m_autoAPTimeout and this->m_autoAPTimeout < time(nullptr) - 10) { //10 seconds no network -> auto ap! - if(this->reconnectCount < 3){ - ++this->reconnectCount; - this->connectWiFi(); - } else { - this->reconnectCount = 1; - this->enableStation(); - this->m_enabledStationByAutoAP = time(nullptr); + // Handling in case of 10 seconds without a successful connect + if(this->m_connectTimeout and this->m_connectTimeout < time(nullptr) - 10) { + ++this->m_connectFailureCount; +#ifndef NDEBUG + Serial.println(String(__FILE__) + ": [Connection] Timeout expired. Looking for alternatives (" + this->m_connectFailureCount + ")..."); +#endif + this->m_connectTimeout = 0; // Disable connection timeout, we will re-enable it with the next iteration, if we still want to connect (and are not in AutoAP mode) + + // We have four options if our connection times out; the fourth is the auto-ap, which is may not available + if(this->m_connectFailureCount % 4 == 3) { + if(OswConfigAllKeys::wifiAutoAP.get()) { + if(!this->m_enableStation) { + this->enableStation(); + this->m_enabledStationByAutoAP = time(nullptr); +#ifndef NDEBUG + Serial.println(String(__FILE__) + ": [AutoAP] Active for " + String(this->m_enabledStationByAutoAPTimeout) + " seconds (password is " + this->m_stationPass + ")."); +#endif + } + } else { #ifndef NDEBUG - Serial.println(String(__FILE__) + ": [AutoAP] Active for " + String(this->m_enabledStationByAutoAPTimeout) + " seconds (password is " + this->m_stationPass + ")."); + Serial.println(String(__FILE__) + ": [AutoAP] Is disabled; no action taken."); #endif + } + } else { + this->selectCredentials(); + this->connectWiFi(); } - } + } if(this->m_queuedNTPUpdate and WiFi.status() == WL_CONNECTED) { OswHal::getInstance()->devices->esp32->triggerNTPUpdate(); @@ -90,19 +114,25 @@ void OswServiceTaskWiFi::loop() { // Disable the auto-ap in case we connected successfully, disabled client or after this->m_enabledStationByAutoAPTimeout seconds const bool autoAPTimedOut = (time(nullptr) - this->m_enabledStationByAutoAP) >= this->m_enabledStationByAutoAPTimeout; if(this->m_enabledStationByAutoAP and (WiFi.status() == WL_CONNECTED or !this->m_enableClient or autoAPTimedOut)) { +#ifndef NDEBUG + Serial.print(String(__FILE__) + ": [AutoAP] Inactive: "); + if(WiFi.status() == WL_CONNECTED) + Serial.println("WiFi connected."); + else if(WiFi.status() == WL_CONNECTED) + Serial.println("WiFi disabled."); + else if(autoAPTimedOut) + Serial.println("Expired."); +#endif this->disableStation(); if(autoAPTimedOut) this->connectWiFi(); this->m_enabledStationByAutoAP = 0; -#ifndef NDEBUG - Serial.println(String(__FILE__) + ": [AutoAP] Inactive."); -#endif } if(this->isConnected() and !this->m_enabledMDNS) { this->m_enabledMDNS = true; if(MDNS.begin(this->m_hostname.c_str())) { - //Announce our HTTP service (always. as we have no way of not-publishing this service ↓) + // Announce our HTTP service (always. As we have no way of not-publishing this service ↓) MDNS.addService("http", "tcp", 80); MDNS.enableWorkstation(); #ifndef NDEBUG @@ -121,6 +151,22 @@ void OswServiceTaskWiFi::loop() { } } +void OswServiceTaskWiFi::selectCredentials() { + if(this->m_connectFailureCount % 4 == 0 and !OswConfigAllKeys::wifiSsid.get().isEmpty()) { + this->m_clientSSID = OswConfigAllKeys::wifiSsid.get(); + this->m_clientPass = OswConfigAllKeys::wifiPass.get(); + } else if(this->m_connectFailureCount % 4 == 1 and !OswConfigAllKeys::fallbackWifiSsid1st.get().isEmpty()) { + this->m_clientSSID = OswConfigAllKeys::fallbackWifiSsid1st.get(); + this->m_clientPass = OswConfigAllKeys::fallbackWifiPass1st.get(); + } else if(this->m_connectFailureCount % 4 == 2 and !OswConfigAllKeys::fallbackWifiSsid2nd.get().isEmpty()) { + this->m_clientSSID = OswConfigAllKeys::fallbackWifiSsid2nd.get(); + this->m_clientPass = OswConfigAllKeys::fallbackWifiPass2nd.get(); + } else if(this->m_connectFailureCount % 4 == 3) { + // Huh? AutoAP should be active now. If not, we can reuse the previous credentials. + } + // Note, in case an SSID is empty we will just retry the previous one... +} + void OswServiceTaskWiFi::stop() { OswServiceTask::stop(); this->disableWiFi(); @@ -131,6 +177,7 @@ void OswServiceTaskWiFi::stop() { */ void OswServiceTaskWiFi::enableWiFi() { this->m_enableWiFi = true; + this->m_connectFailureCount = 0; this->updateWiFiConfig(); } @@ -179,31 +226,16 @@ bool OswServiceTaskWiFi::isWiFiEnabled() { return this->m_enableClient; } -void OswServiceTaskWiFi::loadCredentials(uint8_t reconnectCount) { - if(reconnectCount == 1) { - this->m_clientSSID = OswConfigAllKeys::wifiSsid.get(); - this->m_clientPass = OswConfigAllKeys::wifiPass.get(); - } else if(reconnectCount == 2 and !OswConfigAllKeys::fallbackWifiSsid1st.get().isEmpty()) { - this->m_clientSSID = OswConfigAllKeys::fallbackWifiSsid1st.get(); - this->m_clientPass = OswConfigAllKeys::fallbackWifiPass1st.get(); - } else if(reconnectCount == 3 and !OswConfigAllKeys::fallbackWifiSsid2nd.get().isEmpty()) { - this->m_clientSSID = OswConfigAllKeys::fallbackWifiSsid2nd.get(); - this->m_clientPass = OswConfigAllKeys::fallbackWifiPass2nd.get(); - } else { - // Shit. This should never heppen, as we should already be in station mode (or give up)... - Serial.println(String(__FILE__) + ": [Credentials] Failed to retreive the credentials for the " + reconnectCount + ". attempt?!"); - } -} /** * Connect to the wifi, using the provided credentials from the config... */ void OswServiceTaskWiFi::connectWiFi() { this->m_hostname = OswConfigAllKeys::hostname.get(); - this->m_autoAPTimeout = 0; //First reset to avoid racing conditions - this->loadCredentials(this->reconnectCount); + this->m_connectTimeout = 0; //First reset to avoid racing conditions this->m_enableClient = true; this->updateWiFiConfig(); - if (this->m_clientPass.isEmpty()) { // if Public Wi-Fi without a password + this->selectCredentials(); + if (this->m_clientPass.isEmpty()) { // If public Wi-Fi without a password WiFi.begin(this->m_clientSSID.c_str()); } else { WiFi.begin(this->m_clientSSID.c_str(), this->m_clientPass.c_str()); @@ -211,7 +243,7 @@ void OswServiceTaskWiFi::connectWiFi() { if(!this->m_queuedNTPUpdate) this->m_queuedNTPUpdate = OswConfigAllKeys::wifiAlwaysNTPEnabled.get(); #ifndef NDEBUG - Serial.println(String(__FILE__) + ": [Client] Connecting to SSID " + this->m_clientSSID + "..."); + Serial.println(String(__FILE__) + ": [Client] Connecting to SSID \"" + this->m_clientSSID + "\"..."); #endif } @@ -220,7 +252,7 @@ void OswServiceTaskWiFi::disconnectWiFi() { WiFi.disconnect(false); this->updateWiFiConfig(); #ifndef NDEBUG - Serial.println(String(__FILE__) + ": [Client] Disconnected wifi client..."); + Serial.println(String(__FILE__) + ": [Client] Disconnected."); #endif } @@ -258,7 +290,7 @@ void OswServiceTaskWiFi::disableStation() { WiFi.softAPdisconnect(false); this->updateWiFiConfig(); #ifndef NDEBUG - Serial.println(String(__FILE__) + ": [Station] Disabled station mode..."); + Serial.println(String(__FILE__) + ": [Station] Disabled."); #endif } From 23af12fd367309b58cea986f47ebeed37edeef22 Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Thu, 16 Jun 2022 12:44:46 +0200 Subject: [PATCH 052/116] Added warkaround and fix for webinterface bug --- src/osw_config_keys.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/osw_config_keys.cpp b/src/osw_config_keys.cpp index 60d5d09b7..4089bed55 100644 --- a/src/osw_config_keys.cpp +++ b/src/osw_config_keys.cpp @@ -6,6 +6,16 @@ #include "gfx_util.h" #include "osw_util.h" +/** + * !!!WARNING!!! + * + * Never select the same label for two different keys (inside their constructor)! This will cause a + * "feature" inside the webinterface to be activated, which will lead to an empty data.json to be saved. + * + * There is no way to recover the users data after this. Be caureful! + * + */ + // Add your keys to this namespace (do not forget to also declare them inside the header) namespace OswConfigAllKeys { // TODO Translate all this? @@ -18,11 +28,11 @@ OswConfigKeyBool wifiAlwaysNTPEnabled("k", "WiFi", "Always fetch time (when conn OswConfigKeyBool wifiAutoAP("l", "WiFi", "Enable Auto AP", "When the connection to the wifi fails, just create an own wifi station.", WIFI_AUTO_AP); OswConfigKeyString wifiSsid("a", "WiFi", "1st SSID", "Your wifi name", CONFIG_WIFI_SSID); -OswConfigKeyPassword wifiPass("b", "WiFi", "Password", nullptr, CONFIG_WIFI_PASS); +OswConfigKeyPassword wifiPass("b", "WiFi", "1st Password", nullptr, CONFIG_WIFI_PASS); OswConfigKeyString fallbackWifiSsid1st("a1", "WiFi", "2nd SSID", "Leave empty to disable", CONFIG_FALLBACK_1ST_WIFI_SSID); -OswConfigKeyPassword fallbackWifiPass1st("b1", "WiFi", "Password", nullptr, CONFIG_FALLBACK_1ST_WIFI_PASS); +OswConfigKeyPassword fallbackWifiPass1st("b1", "WiFi", "2nd Password", nullptr, CONFIG_FALLBACK_1ST_WIFI_PASS); OswConfigKeyString fallbackWifiSsid2nd("a2", "WiFi", "3rd SSID", "Leave empty to disable", CONFIG_FALLBACK_2ND_WIFI_SSID); -OswConfigKeyPassword fallbackWifiPass2nd("b2", "WiFi", "Password", nullptr, CONFIG_FALLBACK_2ND_WIFI_PASS); +OswConfigKeyPassword fallbackWifiPass2nd("b2", "WiFi", "3rd Password", nullptr, CONFIG_FALLBACK_2ND_WIFI_PASS); #endif OswConfigKeyShort settingDisplayBrightness("s1", "Display", "Display Brightness", "From 0 to 255", From f02bd7c168102f926b195131245354dd09ecf44a Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Thu, 16 Jun 2022 12:45:37 +0200 Subject: [PATCH 053/116] Added active check and print password in debug mode --- include/services/OswServiceTaskWebserver.h | 1 + src/services/OswServiceTaskWebserver.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/services/OswServiceTaskWebserver.h b/include/services/OswServiceTaskWebserver.h index 706fbabca..b0bca2905 100644 --- a/include/services/OswServiceTaskWebserver.h +++ b/include/services/OswServiceTaskWebserver.h @@ -17,6 +17,7 @@ class OswServiceTaskWebserver : public OswServiceTask { void enableWebserver(); void disableWebserver(); + bool webserverActive(); WebServer* getTaskWebserver() const; String getPassword() const; diff --git a/src/services/OswServiceTaskWebserver.cpp b/src/services/OswServiceTaskWebserver.cpp index f1f232d0c..e40cc19e0 100644 --- a/src/services/OswServiceTaskWebserver.cpp +++ b/src/services/OswServiceTaskWebserver.cpp @@ -312,7 +312,7 @@ void OswServiceTaskWebserver::enableWebserver() { this->m_webserver->collectHeaders(headers, 1); #ifndef NDEBUG - Serial.println(String(__FILE__) + ": Active."); + Serial.println(String(__FILE__) + ": Active (password is " + this->m_uiPassword + ")."); #endif } @@ -329,6 +329,10 @@ void OswServiceTaskWebserver::disableWebserver() { #endif } +bool OswServiceTaskWebserver::webserverActive() { + return this->m_webserver != nullptr; +} + String OswServiceTaskWebserver::getPassword() const { return this->m_uiPassword; } From 945deac259177ca5a0397947bbf6d2b6fa2fbd17 Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Thu, 16 Jun 2022 12:50:50 +0200 Subject: [PATCH 054/116] Implemented low memory handling --- include/osw_hal.h | 1 + include/services/OswServiceManager.h | 5 +-- include/services/OswServiceTaskMemMonitor.h | 2 + include/services/OswServiceTasks.h | 2 - src/hal/display.cpp | 11 +++++- src/services/OswServiceTaskMemMonitor.cpp | 42 +++++++++++++++++++++ src/services/OswServiceTasks.cpp | 4 -- 7 files changed, 55 insertions(+), 12 deletions(-) diff --git a/include/osw_hal.h b/include/osw_hal.h index 8a217c26f..aa4359c03 100644 --- a/include/osw_hal.h +++ b/include/osw_hal.h @@ -82,6 +82,7 @@ class OswHal { void requestEnableDisplayBuffer(); void disableDisplayBuffer(); void enableDisplayBuffer(); + bool displayBufferEnabled(); unsigned long screenOnTime(); unsigned long screenOffTime(); diff --git a/include/services/OswServiceManager.h b/include/services/OswServiceManager.h index 7ec329e47..2e800d7c1 100644 --- a/include/services/OswServiceManager.h +++ b/include/services/OswServiceManager.h @@ -9,9 +9,6 @@ class OswServiceManager { static OswServiceManager instance; return instance; } - // + wifi service needs 1024 - // + webserver another 2048 - // + updater another 1024 //Temp workaround until #137 is done #ifdef OSW_FEATURE_WIFI @@ -19,7 +16,7 @@ class OswServiceManager { #else #define _SERVICE_WIFI 0 #endif - const unsigned workerStackSize = 1024 + ((1024 + 2048 + 1024) * _SERVICE_WIFI); + const unsigned workerStackSize = 1024 + (7168 * _SERVICE_WIFI); // If wifi is active, set to same size as core 0 void setup(); void loop(); diff --git a/include/services/OswServiceTaskMemMonitor.h b/include/services/OswServiceTaskMemMonitor.h index 54151b063..4e34ce09e 100644 --- a/include/services/OswServiceTaskMemMonitor.h +++ b/include/services/OswServiceTaskMemMonitor.h @@ -10,12 +10,14 @@ class OswServiceTaskMemMonitor : public OswServiceTask { virtual void loop() override; void updateLoopTaskStats(); // Call this from the main loop regulary! void printStats(); + bool hasLowMemoryCondition(); ~OswServiceTaskMemMonitor() {}; private: unsigned core0high; unsigned core1high; unsigned heapHigh; + bool lowMemoryCondition = false; }; #endif \ No newline at end of file diff --git a/include/services/OswServiceTasks.h b/include/services/OswServiceTasks.h index 696c02d33..5f7552d83 100644 --- a/include/services/OswServiceTasks.h +++ b/include/services/OswServiceTasks.h @@ -14,9 +14,7 @@ extern OswServiceTaskBLECompanion bleCompanion; //extern OswServiceTaskExample example; extern OswServiceTaskWiFi wifi; extern OswServiceTaskWebserver webserver; -#ifndef NDEBUG extern OswServiceTaskMemMonitor memory; -#endif } extern const unsigned char oswServiceTasksCount; diff --git a/src/hal/display.cpp b/src/hal/display.cpp index 87fd06fdb..6a6ce410a 100644 --- a/src/hal/display.cpp +++ b/src/hal/display.cpp @@ -35,12 +35,19 @@ void OswHal::requestDisableDisplayBuffer() { void OswHal::requestEnableDisplayBuffer() { _requestEnableBuffer = true; } -void OswHal::disableDisplayBuffer() { // +void OswHal::disableDisplayBuffer() { + if(!this->displayBufferEnabled()) + return; canvas->getGraphics2D()->disableBuffer(pixelPainter); } -void OswHal::enableDisplayBuffer() { // +void OswHal::enableDisplayBuffer() { + if(this->displayBufferEnabled()) + return; canvas->getGraphics2D()->enableBuffer(); } +bool OswHal::displayBufferEnabled() { + return canvas->getGraphics2D()->hasBuffer(); +} void OswHal::setupDisplay() { #ifdef ESP32 diff --git a/src/services/OswServiceTaskMemMonitor.cpp b/src/services/OswServiceTaskMemMonitor.cpp index ba7febf65..bf261e216 100644 --- a/src/services/OswServiceTaskMemMonitor.cpp +++ b/src/services/OswServiceTaskMemMonitor.cpp @@ -1,7 +1,11 @@ #include "./services/OswServiceTaskMemMonitor.h" #include "osw_hal.h" +#include "osw_ui.h" #include "services/OswServiceManager.h" +#include "services/OswServiceTasks.h" +#include "services/OswServiceTaskWebserver.h" +#include "services/OswServiceTaskBLECompanion.h" void OswServiceTaskMemMonitor::setup() { OswServiceTask::setup(); @@ -19,6 +23,42 @@ void OswServiceTaskMemMonitor::loop() { this->heapHigh = high; this->printStats(); } + + // Check for a low memory condition and try to free system resources to help out + bool nowLowMemoryCondition = false; + if(OswServiceAllTasks::webserver.webserverActive()) { + if(this->lowMemoryCondition or ESP.getFreeHeap() < 100000) // Keep low memory or enable if less than 100kb available + nowLowMemoryCondition = true; + } +#if SERVICE_BLE_COMPANION == 1 + if(OswServiceAllTasks::bleCompanion.isRunning()) { + if(this->lowMemoryCondition or ESP.getFreeHeap() < 400000) // Keep low memory or enable if less than 400kb available + nowLowMemoryCondition = true; + } +#endif + + if(nowLowMemoryCondition and !this->lowMemoryCondition) + Serial.println(String(__FILE__) + ": Low memory condition! Activating countermeasures..."); + if(!nowLowMemoryCondition and this->lowMemoryCondition) + Serial.println(String(__FILE__) + ": Low memory condition resolved. Deactivating countermeasures..."); + + if(this->lowMemoryCondition != nowLowMemoryCondition) { + OswUI* ui = OswUI::getInstance(); + std::lock_guard noRender(*ui->drawLock); + if(nowLowMemoryCondition) { + OswHal::getInstance()->disableDisplayBuffer(); + Serial.println(String(__FILE__) + ": Disabled display buffering."); + } else { + OswHal::getInstance()->enableDisplayBuffer(); + Serial.println(String(__FILE__) + ": Enabled display buffering."); + } + } + + this->lowMemoryCondition = nowLowMemoryCondition; +} + +bool OswServiceTaskMemMonitor::hasLowMemoryCondition() { + return this->lowMemoryCondition; } /** @@ -37,6 +77,7 @@ void OswServiceTaskMemMonitor::updateLoopTaskStats() { * Send a overview regarding the current stack watermarks (core 0&1), heap watermarks and heap useage to serial */ void OswServiceTaskMemMonitor::printStats() { +#ifndef NDEBUG Serial.println("========= Memory Monitor ========="); Serial.print("core 0 (high):\t"); Serial.print(OswServiceManager::getInstance().workerStackSize - this->core0high); @@ -77,4 +118,5 @@ void OswServiceTaskMemMonitor::printStats() { #endif // TODO Maybe fetch current largest available heap size and calc "fragmentation" percentage. +#endif } diff --git a/src/services/OswServiceTasks.cpp b/src/services/OswServiceTasks.cpp index d5f23082f..9e3df9873 100644 --- a/src/services/OswServiceTasks.cpp +++ b/src/services/OswServiceTasks.cpp @@ -23,9 +23,7 @@ OswServiceTaskGPS gps; OswServiceTaskWiFi wifi; OswServiceTaskWebserver webserver; #endif -#ifndef NDEBUG OswServiceTaskMemMonitor memory; -#endif } // namespace OswServiceAllTasks OswServiceTask* oswServiceTasks[] = { @@ -40,8 +38,6 @@ OswServiceTask* oswServiceTasks[] = { #ifdef OSW_FEATURE_WIFI & OswServiceAllTasks::wifi, &OswServiceAllTasks::webserver, #endif -#ifndef NDEBUG & OswServiceAllTasks::memory -#endif }; const unsigned char oswServiceTasksCount = OswUtil::size(oswServiceTasks); From 29e7f56bb358eccbfc370d1183ab6c360d8dec30 Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Thu, 16 Jun 2022 12:52:47 +0200 Subject: [PATCH 055/116] Reduce full screen refresh during low memory --- include/osw_ui.h | 2 ++ src/osw_ui.cpp | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/osw_ui.h b/include/osw_ui.h index 79e0280db..58c56bd9c 100644 --- a/include/osw_ui.h +++ b/include/osw_ui.h @@ -59,6 +59,8 @@ class OswUI { unsigned long mTargetFPS = 30; String mProgressText; OswUIProgress* mProgressBar = nullptr; + time_t lastFlush = 0; + time_t lastBGFlush = 0; }; #endif diff --git a/src/osw_ui.cpp b/src/osw_ui.cpp index a26e51f15..58fda2ecb 100644 --- a/src/osw_ui.cpp +++ b/src/osw_ui.cpp @@ -69,10 +69,15 @@ void OswUI::setTextCursor(Button btn) { void OswUI::loop(OswAppSwitcher& mainAppSwitcher, uint16_t& mainAppIndex) { std::lock_guard guard(*this->drawLock); - static time_t lastFlush = 0; // BG - OswHal::getInstance()->gfx()->fill(this->getBackgroundColor()); + if(OswHal::getInstance()->displayBufferEnabled()) + OswHal::getInstance()->gfx()->fill(this->getBackgroundColor()); + else if(this->lastBGFlush < millis() - 10000) { + // In case the buffering is inactive, only flush every 10 seconds the whole buffer + OswHal::getInstance()->gfx()->fill(this->getBackgroundColor()); + this->lastBGFlush = millis(); + } this->resetTextColors(); if(this->mProgressBar == nullptr) { From 3b721d60126e82fcabbec69e11d9dc4dbeb2699e Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Thu, 16 Jun 2022 12:53:18 +0200 Subject: [PATCH 056/116] Added low memory indicator --- src/overlays/overlays.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/overlays/overlays.cpp b/src/overlays/overlays.cpp index 3dbc8c824..999ffbd25 100644 --- a/src/overlays/overlays.cpp +++ b/src/overlays/overlays.cpp @@ -1,5 +1,6 @@ #include "./overlays/overlays.h" +#include #include #include @@ -43,6 +44,19 @@ void drawWiFi(uint16_t x, uint16_t y) { } #endif +void drawLowMemory(uint16_t x, uint16_t y) { + if (!OswServiceAllTasks::memory.hasLowMemoryCondition()) + return; + Graphics2DPrint* gfx = OswHal::getInstance()->gfx(); + gfx->fillFrame(x + 2, y + 2, 11, 11, OswUI::getInstance()->getDangerColor()); + gfx->drawLine(x, y + 3, x + 14, y + 3, OswUI::getInstance()->getDangerColor()); + gfx->drawLine(x, y + 7, x + 14, y + 7, OswUI::getInstance()->getDangerColor()); + gfx->drawLine(x, y + 11, x + 14, y + 11, OswUI::getInstance()->getDangerColor()); + gfx->drawLine(x + 3, y, x + 3, y + 14, OswUI::getInstance()->getDangerColor()); + gfx->drawLine(x + 7, y, x + 7, y + 14, OswUI::getInstance()->getDangerColor()); + gfx->drawLine(x + 11, y, x + 11, y + 14, OswUI::getInstance()->getDangerColor()); +} + void drawOverlays() { bool drawBat = true; #ifdef OSW_FEATURE_WIFI @@ -50,6 +64,8 @@ void drawOverlays() { drawBat = !OswServiceAllTasks::wifi.isEnabled(); #endif + drawLowMemory(84, 4); + if (OswHal::getInstance()->isCharging()) drawUsbConnected(120 - 16, 6); // width is 31 else if (drawBat) From 39d674ae51e4495399042602d1dc44ff5bcab686 Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Thu, 16 Jun 2022 12:54:10 +0200 Subject: [PATCH 057/116] Removed double screen clear --- src/apps/tools/OswAppFitnessStats.cpp | 1 - src/apps/tools/OswAppKcalStats.cpp | 1 - src/apps/tools/OswAppStepStats.cpp | 1 - src/apps/tools/water_level.cpp | 1 - src/apps/watchfaces/OswAppWatchface.cpp | 2 -- src/apps/watchfaces/OswAppWatchfaceBinary.cpp | 2 -- src/apps/watchfaces/OswAppWatchfaceDigital.cpp | 2 -- src/apps/watchfaces/OswAppWatchfaceDual.cpp | 2 -- src/apps/watchfaces/OswAppWatchfaceFitness.cpp | 2 -- src/apps/watchfaces/OswAppWatchfaceMix.cpp | 2 -- 10 files changed, 16 deletions(-) diff --git a/src/apps/tools/OswAppFitnessStats.cpp b/src/apps/tools/OswAppFitnessStats.cpp index 3d3e2026a..87cb77b4e 100644 --- a/src/apps/tools/OswAppFitnessStats.cpp +++ b/src/apps/tools/OswAppFitnessStats.cpp @@ -54,7 +54,6 @@ void OswAppFitnessStats::setup() { void OswAppFitnessStats::loop() { OswHal* hal = OswHal::getInstance(); - hal->gfx()->fill(ui->getBackgroundColor()); showFitnessTracking(); hal->requestFlush(); } diff --git a/src/apps/tools/OswAppKcalStats.cpp b/src/apps/tools/OswAppKcalStats.cpp index 9477bb71d..373896282 100644 --- a/src/apps/tools/OswAppKcalStats.cpp +++ b/src/apps/tools/OswAppKcalStats.cpp @@ -109,7 +109,6 @@ void OswAppKcalStats::loop() { if (hal->btnHasGoneDown(BUTTON_2)) { this->cursorPos = this->cursorPos - 1 < 0 ? 0 : this->cursorPos - 1; } - hal->gfx()->fill(ui->getBackgroundColor()); showCurvedChart(); diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index c3a52376d..0b8fbef0d 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -78,7 +78,6 @@ void OswAppStepStats::showStickChart() { void OswAppStepStats::setup() {} void OswAppStepStats::loop() { OswHal* hal = OswHal::getInstance(); - hal->gfx()->fill(ui->getBackgroundColor()); showStickChart(); hal->requestFlush(); } diff --git a/src/apps/tools/water_level.cpp b/src/apps/tools/water_level.cpp index ce073c9ed..817fd07e5 100644 --- a/src/apps/tools/water_level.cpp +++ b/src/apps/tools/water_level.cpp @@ -112,7 +112,6 @@ void OswAppWaterLevel::barsDisplay() { int displayMode = 1; void OswAppWaterLevel::loop() { OswHal* hal = OswHal::getInstance(); - hal->getCanvas()->fillScreen(ui->getBackgroundColor()); // to better understand the accelerometer values use the debug function // debug(hal); diff --git a/src/apps/watchfaces/OswAppWatchface.cpp b/src/apps/watchfaces/OswAppWatchface.cpp index 1d553a6ac..d87203d8c 100644 --- a/src/apps/watchfaces/OswAppWatchface.cpp +++ b/src/apps/watchfaces/OswAppWatchface.cpp @@ -145,8 +145,6 @@ void OswAppWatchface::loop() { bgGif->loop(hal); // lastDraw = millis(); // } -#else - hal->gfx()->fill(ui->getBackgroundColor()); #endif #ifdef MATRIX diff --git a/src/apps/watchfaces/OswAppWatchfaceBinary.cpp b/src/apps/watchfaces/OswAppWatchfaceBinary.cpp index 5e4ab9e8d..910ed2e37 100644 --- a/src/apps/watchfaces/OswAppWatchfaceBinary.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceBinary.cpp @@ -26,8 +26,6 @@ void OswAppWatchfaceBinary::drawWatch(Graphics2D* gfx2d) { uint16_t width = hal->gfx()->getWidth(); uint16_t height = hal->gfx()->getHeight(); - hal->gfx()->fill(ui->getBackgroundColor()); - //hours for(uint8_t i = 0; i < 5 ; i++ ) { uint32_t b = pow(2, i); diff --git a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp index ac70d00f0..c713dba51 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp @@ -146,8 +146,6 @@ void OswAppWatchfaceDigital::loop() { hal->decreaseBrightness(25); } - hal->gfx()->fill(ui->getBackgroundColor()); - digitalWatch(OswConfigAllKeys::timeZone.get(), 2, 80, 120); #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 diff --git a/src/apps/watchfaces/OswAppWatchfaceDual.cpp b/src/apps/watchfaces/OswAppWatchfaceDual.cpp index 66af5bc54..1c2ce5825 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDual.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDual.cpp @@ -54,8 +54,6 @@ void OswAppWatchfaceDual::loop() { hal->decreaseBrightness(25); } - hal->gfx()->fill(ui->getBackgroundColor()); - // Set Dual Size hal->gfx()->setTextSize(2); uint8_t mid_little = hal->gfx()->getTextOfsetRows(0.5); diff --git a/src/apps/watchfaces/OswAppWatchfaceFitness.cpp b/src/apps/watchfaces/OswAppWatchfaceFitness.cpp index 11c4d33cf..d31c232b5 100644 --- a/src/apps/watchfaces/OswAppWatchfaceFitness.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceFitness.cpp @@ -152,8 +152,6 @@ void OswAppWatchfaceFitness::loop() { hal->decreaseBrightness(25); } - hal->gfx()->fill(ui->getBackgroundColor()); - dateDisplay(); digitalWatchDisplay(); diff --git a/src/apps/watchfaces/OswAppWatchfaceMix.cpp b/src/apps/watchfaces/OswAppWatchfaceMix.cpp index 8189a7f7e..07ecdd98c 100644 --- a/src/apps/watchfaces/OswAppWatchfaceMix.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceMix.cpp @@ -120,8 +120,6 @@ void OswAppWatchfaceMix::loop() { hal->decreaseBrightness(25); } - hal->gfx()->fill(ui->getBackgroundColor()); - analogWatchDisplay(); dateDisplay(); digitalWatchDisplay(); From 1ee8d0b659bb1dc35da96b47e7c3d55eaee12e04 Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Thu, 16 Jun 2022 13:03:59 +0200 Subject: [PATCH 058/116] Added "connecting" indicator --- src/apps/tools/OswAppWebserver.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/apps/tools/OswAppWebserver.cpp b/src/apps/tools/OswAppWebserver.cpp index 76b474431..1d283f62d 100644 --- a/src/apps/tools/OswAppWebserver.cpp +++ b/src/apps/tools/OswAppWebserver.cpp @@ -22,7 +22,10 @@ void OswAppWebserver::loop() { if (OswServiceAllTasks::wifi.isConnected()) { hal->gfx()->print(LANG_DISCONNECT); } else { - hal->gfx()->print(LANG_CONNECT); + if(OswServiceAllTasks::wifi.isEnabled()) + hal->gfx()->print("..."); + else + hal->gfx()->print(LANG_CONNECT); } if (hal->btnHasGoneDown(BUTTON_3)) { From 9fa77435a3917f8f9556fa1b0f477e472b021d82 Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Thu, 16 Jun 2022 13:26:34 +0200 Subject: [PATCH 059/116] Added os and platform information --- .../tools/{print_debug.h => OswAppPrintDebug.h} | 7 ++++++- .../tools/{print_debug.cpp => OswAppPrintDebug.cpp} | 13 ++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) rename include/apps/tools/{print_debug.h => OswAppPrintDebug.h} (71%) rename src/apps/tools/{print_debug.cpp => OswAppPrintDebug.cpp} (95%) diff --git a/include/apps/tools/print_debug.h b/include/apps/tools/OswAppPrintDebug.h similarity index 71% rename from include/apps/tools/print_debug.h rename to include/apps/tools/OswAppPrintDebug.h index 8d326e8c1..e2214eb60 100644 --- a/include/apps/tools/print_debug.h +++ b/include/apps/tools/OswAppPrintDebug.h @@ -12,4 +12,9 @@ class OswAppPrintDebug : public OswApp { ~OswAppPrintDebug() {}; private: -}; \ No newline at end of file + uint8_t y = 32; + uint8_t x = 52; + void printStatus(const char* setting, const char* value); +}; + +#endif \ No newline at end of file diff --git a/src/apps/tools/print_debug.cpp b/src/apps/tools/OswAppPrintDebug.cpp similarity index 95% rename from src/apps/tools/print_debug.cpp rename to src/apps/tools/OswAppPrintDebug.cpp index a55a237d5..4441cd003 100644 --- a/src/apps/tools/print_debug.cpp +++ b/src/apps/tools/OswAppPrintDebug.cpp @@ -12,9 +12,7 @@ #define SERIAL_BUF_SIZE 14 -uint8_t y = 32; -uint8_t x = 52; -void printStatus(const char* setting, const char* value) { +void OswAppPrintDebug::printStatus(const char* setting, const char* value) { OswHal* hal = OswHal::getInstance(); hal->gfx()->setTextCursor(x, y); hal->gfx()->print(setting); @@ -22,6 +20,7 @@ void printStatus(const char* setting, const char* value) { hal->gfx()->print(value); y += 8; } + void OswAppPrintDebug::setup() { #if defined(GPS_EDITION) || defined(GPS_EDITION_ROTATED) OswHal::getInstance()->gpsFullOnGpsGlonassBeidu(); @@ -38,12 +37,11 @@ void OswAppPrintDebug::loop() { #endif y = 32; - printStatus("Compiled", (String(__DATE__) + " " + String(__TIME__)).c_str()); printStatus("RAM", (String(ESP.getHeapSize() - ESP.getFreeHeap()) + "B / " + ESP.getHeapSize() + "B").c_str()); - #ifdef BOARD_HAS_PSRAM printStatus("PSRAM", (String(ESP.getPsramSize() - ESP.getFreePsram()) + "B / " + String(ESP.getPsramSize()) + "B").c_str()); #endif + #if OSW_PLATFORM_ENVIRONMENT == 1 #if OSW_PLATFORM_ENVIRONMENT_TEMPERATURE == 1 printStatus("Temperature", String(hal->environment->getTemperature() + String("C")).c_str()); @@ -76,6 +74,10 @@ void OswAppPrintDebug::loop() { wifiDisabled = !OswServiceAllTasks::wifi.isEnabled(); #endif printStatus("Battery (Analog)", (wifiDisabled ? String(hal->getBatteryRaw()) : String("WiFi active!")).c_str()); + printStatus("Hash", (String(GIT_COMMIT_HASH) + " (" + String(GIT_BRANCH_NAME) + ")").c_str()); + printStatus("Platform", String(PIO_ENV_NAME).c_str()); + printStatus("Compiled", (String(__DATE__) + " " + String(__TIME__)).c_str()); + printStatus("Button 1", hal->btnIsDown(BUTTON_1) ? "DOWN" : "UP"); printStatus("Button 2", hal->btnIsDown(BUTTON_2) ? "DOWN" : "UP"); printStatus("Button 3", hal->btnIsDown(BUTTON_3) ? "DOWN" : "UP"); @@ -122,6 +124,7 @@ void OswAppPrintDebug::loop() { } } #endif + hal->requestFlush(); } From 566d3da6b4b0c5dfb53e224c5eed247c87355c0d Mon Sep 17 00:00:00 2001 From: Simon Beginn Date: Thu, 16 Jun 2022 13:45:45 +0200 Subject: [PATCH 060/116] Fix broken header --- include/apps/tools/OswAppPrintDebug.h | 4 +--- src/apps/tools/OswAppPrintDebug.cpp | 2 +- src/main.cpp | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/include/apps/tools/OswAppPrintDebug.h b/include/apps/tools/OswAppPrintDebug.h index e2214eb60..07ec0f03c 100644 --- a/include/apps/tools/OswAppPrintDebug.h +++ b/include/apps/tools/OswAppPrintDebug.h @@ -15,6 +15,4 @@ class OswAppPrintDebug : public OswApp { uint8_t y = 32; uint8_t x = 52; void printStatus(const char* setting, const char* value); -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/src/apps/tools/OswAppPrintDebug.cpp b/src/apps/tools/OswAppPrintDebug.cpp index 4441cd003..f02d407ef 100644 --- a/src/apps/tools/OswAppPrintDebug.cpp +++ b/src/apps/tools/OswAppPrintDebug.cpp @@ -1,5 +1,5 @@ -#include "./apps/tools/print_debug.h" +#include "./apps/tools/OswAppPrintDebug.h" #include #include diff --git a/src/main.cpp b/src/main.cpp index 54983d350..209ae9a19 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,7 +34,7 @@ #include "./apps/main/stopwatch.h" #include "./apps/main/switcher.h" #include "./apps/tools/button_test.h" -#include "./apps/tools/print_debug.h" +#include "./apps/tools/OswAppPrintDebug.h" #include "./apps/tools/time_config.h" #include "./apps/tools/water_level.h" #include "./apps/tools/OswAppFitnessStats.h" From 496f4e0b5e437b3c56c918dc515670a5e8eb6d19 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Mon, 20 Jun 2022 23:44:31 +0200 Subject: [PATCH 061/116] Fix for spamming of "Accessing key id e" --- include/apps/watchfaces/OswAppWatchfaceDigital.h | 2 ++ src/apps/watchfaces/OswAppWatchfaceDigital.cpp | 12 +++++++++++- src/osw_config.cpp | 4 +++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/apps/watchfaces/OswAppWatchfaceDigital.h b/include/apps/watchfaces/OswAppWatchfaceDigital.h index 3905561fb..a71bb24d9 100644 --- a/include/apps/watchfaces/OswAppWatchfaceDigital.h +++ b/include/apps/watchfaces/OswAppWatchfaceDigital.h @@ -15,6 +15,7 @@ class OswAppWatchfaceDigital : public OswApp { virtual void stop() override; ~OswAppWatchfaceDigital() {}; inline static uint8_t getDateFormat(); // Return 0 : mm/dd/yyyy 1 : dd.mm.yyyy 2 : yy.mm/dd + static void refreshDateFormatCache(); static void drawSteps(); static void digitalWatch(short timeZone, uint8_t fontSize, uint8_t dateCoordY, uint8_t timeCoordY); static void timeOutput(uint32_t hour, uint32_t minute, uint32_t second, bool showSecond = true); @@ -22,4 +23,5 @@ class OswAppWatchfaceDigital : public OswApp { private: OswUI* ui; + static uint8_t dateFormatCache; }; \ No newline at end of file diff --git a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp index c713dba51..84e85b07a 100644 --- a/src/apps/watchfaces/OswAppWatchfaceDigital.cpp +++ b/src/apps/watchfaces/OswAppWatchfaceDigital.cpp @@ -8,8 +8,18 @@ #include #include +uint8_t OswAppWatchfaceDigital::dateFormatCache = 42; + uint8_t OswAppWatchfaceDigital::getDateFormat() { - return (OswConfigAllKeys::dateFormat.get() == "mm/dd/yyyy" ? 1 : (OswConfigAllKeys::dateFormat.get() == "dd.mm.yyyy" ? 2 : 3)); + if(OswAppWatchfaceDigital::dateFormatCache == 42) + OswAppWatchfaceDigital::refreshDateFormatCache(); + // Note, that we are using the cache here, as this function is commonly evaluated with every frame drawn! + return OswAppWatchfaceDigital::dateFormatCache; +} + +void OswAppWatchfaceDigital::refreshDateFormatCache() { + String format = OswConfigAllKeys::dateFormat.get(); + OswAppWatchfaceDigital::dateFormatCache = (format == "mm/dd/yyyy" ? 1 : (format == "dd.mm.yyyy" ? 2 : 3)); } void OswAppWatchfaceDigital::dateOutput(uint32_t yearInt, uint32_t monthInt, uint32_t dayInt) { diff --git a/src/osw_config.cpp b/src/osw_config.cpp index e217c33c3..ccd43382a 100644 --- a/src/osw_config.cpp +++ b/src/osw_config.cpp @@ -7,6 +7,7 @@ #include "osw_config_keys.h" #include "osw_ui.h" // For color reloading +#include "apps/watchfaces/OswAppWatchfaceDigital.h" OswConfig OswConfig::instance = OswConfig(); @@ -153,6 +154,7 @@ void OswConfig::parseDataJSON(const char* json) { #endif } - // Reload UI colors + // Reload parts of the OS, which buffer values OswUI::getInstance()->resetTextColors(); + OswAppWatchfaceDigital::refreshDateFormatCache(); } From 52674093e253933a2a38d9226cf7ed623f61fd13 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Wed, 22 Jun 2022 00:04:15 +0900 Subject: [PATCH 062/116] HAL : enhancements, get last-week steps in getStepsOnDay() --- include/hal/environment.h | 2 +- src/hal/environment.cpp | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/hal/environment.h b/include/hal/environment.h index 889ccdaa5..ac4f7336d 100644 --- a/include/hal/environment.h +++ b/include/hal/environment.h @@ -39,7 +39,7 @@ class OswHal::Environment { uint32_t getStepsTotal(); uint32_t getStepsTotalWeek(); #ifdef OSW_FEATURE_STATS_STEPS - uint32_t getStepsOnDay(uint8_t dayOfWeek); + uint32_t getStepsOnDay(uint8_t dayOfWeek, bool lastWeek = false); #endif #endif diff --git a/src/hal/environment.cpp b/src/hal/environment.cpp index 3ccaa07a6..9f4f50d33 100644 --- a/src/hal/environment.cpp +++ b/src/hal/environment.cpp @@ -176,13 +176,17 @@ uint32_t OswHal::Environment::getStepsToday() { } #ifdef OSW_FEATURE_STATS_STEPS -uint32_t OswHal::Environment::getStepsOnDay(uint8_t dayOfWeek) { +uint32_t OswHal::Environment::getStepsOnDay(uint8_t dayOfWeek, bool lastWeek) { uint32_t day = 0; uint32_t weekday = 0; OswHal::getInstance()->getLocalDate(&day, &weekday); - if (dayOfWeek == weekday) + + if (!lastWeek and dayOfWeek == weekday) return this->getStepsToday(); - return this->_stepsCache[dayOfWeek]; + else if(!lastWeek or (lastWeek and dayOfWeek == weekday)) + return this->_stepsCache[dayOfWeek]; + else + return 0; // In that case we don't have any history left anymore - just reply with a zero... } #endif uint32_t OswHal::Environment::getStepsTotal() { From 3ce8582e869227147c310c4448788d0f6d9e7dac Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 21 Jun 2022 15:20:45 +0000 Subject: [PATCH 063/116] Applied formatting --- src/hal/environment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hal/environment.cpp b/src/hal/environment.cpp index 9f4f50d33..04182b2c7 100644 --- a/src/hal/environment.cpp +++ b/src/hal/environment.cpp @@ -181,7 +181,7 @@ uint32_t OswHal::Environment::getStepsOnDay(uint8_t dayOfWeek, bool lastWeek) { uint32_t weekday = 0; OswHal::getInstance()->getLocalDate(&day, &weekday); - if (!lastWeek and dayOfWeek == weekday) + if (!lastWeek and dayOfWeek == weekday) return this->getStepsToday(); else if(!lastWeek or (lastWeek and dayOfWeek == weekday)) return this->_stepsCache[dayOfWeek]; From 026c4ed10c2cadfc6f6c9511ddea9208826d1c9c Mon Sep 17 00:00:00 2001 From: simonmicro Date: Tue, 21 Jun 2022 17:54:31 +0200 Subject: [PATCH 064/116] Added "..." also to time config --- .../apps/tools/{time_config.h => OswAppTimeConfig.h} | 0 .../tools/{time_config.cpp => OswAppTimeConfig.cpp} | 12 ++++++++---- src/main.cpp | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) rename include/apps/tools/{time_config.h => OswAppTimeConfig.h} (100%) rename src/apps/tools/{time_config.cpp => OswAppTimeConfig.cpp} (96%) diff --git a/include/apps/tools/time_config.h b/include/apps/tools/OswAppTimeConfig.h similarity index 100% rename from include/apps/tools/time_config.h rename to include/apps/tools/OswAppTimeConfig.h diff --git a/src/apps/tools/time_config.cpp b/src/apps/tools/OswAppTimeConfig.cpp similarity index 96% rename from src/apps/tools/time_config.cpp rename to src/apps/tools/OswAppTimeConfig.cpp index ca7d1436f..5dd25411c 100644 --- a/src/apps/tools/time_config.cpp +++ b/src/apps/tools/OswAppTimeConfig.cpp @@ -1,4 +1,4 @@ -#include "./apps/tools/time_config.h" +#include "./apps/tools/OswAppTimeConfig.h" #include #include @@ -158,9 +158,13 @@ void OswAppTimeConfig::loop() { if (OswServiceAllTasks::wifi.isConnected()) { hal->gfx()->print(LANG_DISCONNECT); } else { - hal->gfx()->print(LANG_CONNECT); - OswUI::getInstance()->setTextCursor(BUTTON_2); - hal->gfx()->print(LANG_MANUALLY); + if(OswServiceAllTasks::wifi.isEnabled()) + hal->gfx()->print("..."); + else { + hal->gfx()->print(LANG_CONNECT); + OswUI::getInstance()->setTextCursor(BUTTON_2); + hal->gfx()->print(LANG_MANUALLY); + } } if (hal->btnHasGoneDown(BUTTON_3)) { diff --git a/src/main.cpp b/src/main.cpp index 209ae9a19..a69ae1d28 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,7 +35,7 @@ #include "./apps/main/switcher.h" #include "./apps/tools/button_test.h" #include "./apps/tools/OswAppPrintDebug.h" -#include "./apps/tools/time_config.h" +#include "./apps/tools/OswAppTimeConfig.h" #include "./apps/tools/water_level.h" #include "./apps/tools/OswAppFitnessStats.h" #ifdef OSW_FEATURE_STATS_STEPS From 35d3fd9a5dec77240d0fcd1b7c9af53e56930018 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Tue, 21 Jun 2022 18:00:33 +0200 Subject: [PATCH 065/116] Removed double credential selection --- src/services/OswServiceTaskWiFi.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/services/OswServiceTaskWiFi.cpp b/src/services/OswServiceTaskWiFi.cpp index 16f119676..f8338947a 100644 --- a/src/services/OswServiceTaskWiFi.cpp +++ b/src/services/OswServiceTaskWiFi.cpp @@ -85,10 +85,8 @@ void OswServiceTaskWiFi::loop() { Serial.println(String(__FILE__) + ": [AutoAP] Is disabled; no action taken."); #endif } - } else { - this->selectCredentials(); + } else this->connectWiFi(); - } } if(this->m_queuedNTPUpdate and WiFi.status() == WL_CONNECTED) { From 4aa54785a145b6799ed462bd47b34327c48107ce Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Wed, 22 Jun 2022 13:47:23 +0900 Subject: [PATCH 066/116] CI : add check the feature resolve #241 --- .github/workflows/test-FEATURE.yml | 75 ++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 .github/workflows/test-FEATURE.yml diff --git a/.github/workflows/test-FEATURE.yml b/.github/workflows/test-FEATURE.yml new file mode 100644 index 000000000..d388d5b70 --- /dev/null +++ b/.github/workflows/test-FEATURE.yml @@ -0,0 +1,75 @@ +name: OSW-FEATURE-test + +on: + workflow_dispatch: + push: + pull_request: + branches: [ master, develop ] + +jobs: + Find-feature: + runs-on: ubuntu-latest + steps: + - name: Checkout repository and submodules + uses: actions/checkout@v2 + with: + submodules: recursive + - id: get-flag + run: | + echo "::set-output name=feature::$(F=$(cat feature-flag.md | grep "flag:" | sed -e 's/flag://' | tr ']\n' ' ');F=($F);jq --compact-output --null-input '$ARGS.positional' --args -- "${F[@]}")" + - id: default_mod + run: | + echo "::set-output name=default_model::$(R=$(x=$(cat platformio.ini | grep "defau"); echo "${x:15}"); R=($R);jq --compact-output --null-input '$ARGS.positional' --args -- "${R[@]}")" + - id: default_lang + run: | + echo "::set-output name=default_language::$(A=$(if [ -e include/locales/en-US.h ]; then s=$(ls include/locales/en-US.h); else s=$(ls include/locales/*.h -1 | head -1); fi; echo ${s:16:5});A=($A);jq --compact-output --null-input '$ARGS.positional' --args -- "${A[@]}")" + + outputs: + feature: ${{ steps.get-flag.outputs.feature }} + default_model: ${{ steps.default_mod.outputs.default_model }} + default_language: ${{ steps.default_lang.outputs.default_language }} + + build-OSW: + needs: Find-feature + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + feature: ${{ fromJson(needs.Find-feature.outputs.feature) }} + model: ${{ fromJson(needs.Find-feature.outputs.default_model) }} + language: ${{ fromJson(needs.Find-feature.outputs.default_language) }} + steps: + - name: Checkout repository and submodules + uses: actions/checkout@v2 + with: + submodules: recursive + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: cache-${{ secrets.CACHE_VERSION }}-${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Cache PlatformIO + uses: actions/cache@v2 + with: + path: ~/.platformio + key: cache-${{ secrets.CACHE_VERSION }}-${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + - name: Install swig + run: sudo apt-get update && sudo apt-get -y install swig + - name: Set up Python + uses: actions/setup-python@v2 + - name: Install PlatformIO + run: python -m pip install --upgrade pip && pip install --upgrade platformio + + - name: Rename config + run: mv include/config.h.example include/config.h + + - name: Compile language ${{ matrix.language }} model ${{ matrix.model }} feature ${{ matrix.feature }} + run: python3 .github/buildEverything.py -l ${{ matrix.language }} -m ${{ matrix.model }} -f ${{ matrix.feature }} + - name: Upload firmware artifacts + uses: actions/upload-artifact@v2 + with: + name: firmwares + path: | + *.bin From a9435e7f5a2fb7ea60cabde218f918ff11d504ac Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Thu, 23 Jun 2022 02:02:14 +0900 Subject: [PATCH 067/116] OswAppStepStats : replace value --- src/apps/tools/OswAppStepStats.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index c3a52376d..50f06503a 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -48,8 +48,8 @@ void OswAppStepStats::showStickChart() { uint8_t coord_x = 30; - hal->gfx()->drawThickTick(coord_x, 150, 0, 240 - (coord_x * 2), 90, 2, ui->getPrimaryColor()); - hal->gfx()->drawLine(120, 165, 120, 220, ui->getPrimaryColor()); // long front + hal->gfx()->drawThickTick(coord_x, 150, 0, DISP_W - (coord_x * 2), 90, 2, ui->getPrimaryColor()); + hal->gfx()->drawLine(DISP_W / 2, 165, DISP_W / 2, 220, ui->getPrimaryColor()); // long front hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); From e257b8133f4a89405e09118b27146ddd90b08206 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Fri, 24 Jun 2022 22:14:11 +0900 Subject: [PATCH 068/116] OswAppWatchface : replace matrix to animation word --- include/apps/watchfaces/OswAppWatchface.h | 4 ++-- src/apps/watchfaces/OswAppWatchface.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/apps/watchfaces/OswAppWatchface.h b/include/apps/watchfaces/OswAppWatchface.h index 9c40b8383..ea8c4a18e 100644 --- a/include/apps/watchfaces/OswAppWatchface.h +++ b/include/apps/watchfaces/OswAppWatchface.h @@ -4,7 +4,7 @@ #include #include "osw_app.h" -#ifdef MATRIX +#ifdef ANIMATION #include #endif @@ -24,7 +24,7 @@ class OswAppWatchface : public OswApp { private: OswUI* ui; void drawWatch(); -#ifdef MATRIX +#ifdef ANIMATION AnimMatrix* matrix; #endif }; \ No newline at end of file diff --git a/src/apps/watchfaces/OswAppWatchface.cpp b/src/apps/watchfaces/OswAppWatchface.cpp index 1d553a6ac..7afd1264a 100644 --- a/src/apps/watchfaces/OswAppWatchface.cpp +++ b/src/apps/watchfaces/OswAppWatchface.cpp @@ -2,7 +2,7 @@ #include "./apps/watchfaces/OswAppWatchface.h" // #define GIF_BG -#ifdef MATRIX +#ifdef ANIMATION #include #endif @@ -125,7 +125,7 @@ void OswAppWatchface::setup() { #ifdef GIF_BG bgGif->setup(hal); #endif -#ifdef MATRIX +#ifdef ANIMATION // create new animation object adapted for OSW screen this->matrix = new AnimMatrix(OswHal::getInstance()->gfx(), "GATC", 4, 16, 2); #endif @@ -149,7 +149,7 @@ void OswAppWatchface::loop() { hal->gfx()->fill(ui->getBackgroundColor()); #endif -#ifdef MATRIX +#ifdef ANIMATION matrix->loop(hal->gfx()); #endif drawWatch(); From 2f01867748600f71ecff024d96f2fd3139eee7ff Mon Sep 17 00:00:00 2001 From: simonmicro Date: Tue, 28 Jun 2022 15:27:29 +0200 Subject: [PATCH 069/116] Fix for inactive display buffer --- src/services/OswServiceTaskWebserver.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/services/OswServiceTaskWebserver.cpp b/src/services/OswServiceTaskWebserver.cpp index e40cc19e0..8bc39b548 100644 --- a/src/services/OswServiceTaskWebserver.cpp +++ b/src/services/OswServiceTaskWebserver.cpp @@ -227,6 +227,15 @@ void OswServiceTaskWebserver::handleScreenServer() { long contentLength = DISP_W * DISP_H * 3; uint8_t buf[3 * DISP_W]; + // Note that we are using the screen buffer here, but is could be inactive right now -> activate and wait a while if it is + if(!OswHal::getInstance()->displayBufferEnabled()) { + { + std::lock_guard noRender(OswHal::getInstance()->drawLock); + OswHal::getInstance()->enableDisplayBuffer(); + } + sleep(1); // After this a new frame should be available! + } + this->m_webserver->client().write("HTTP/1.1 200 OK"); this->m_webserver->client().write((String("\r\nContent-Length: ") + String(contentLength)).c_str()); this->m_webserver->client().write("\r\nContent-Type: application/octet-stream"); From 7c4952f8fa1c4ea76ea6a76ca710e3f27d27812d Mon Sep 17 00:00:00 2001 From: simonmicro Date: Tue, 28 Jun 2022 15:29:08 +0200 Subject: [PATCH 070/116] Disable buffer after use again --- src/services/OswServiceTaskWebserver.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/services/OswServiceTaskWebserver.cpp b/src/services/OswServiceTaskWebserver.cpp index 8bc39b548..d0e74a050 100644 --- a/src/services/OswServiceTaskWebserver.cpp +++ b/src/services/OswServiceTaskWebserver.cpp @@ -224,18 +224,20 @@ void OswServiceTaskWebserver::handleDataJson() { void OswServiceTaskWebserver::handleScreenServer() { std::lock_guard lock(*OswUI::getInstance()->drawLock); - long contentLength = DISP_W * DISP_H * 3; - uint8_t buf[3 * DISP_W]; - // Note that we are using the screen buffer here, but is could be inactive right now -> activate and wait a while if it is + bool disableBufferAgain = false; if(!OswHal::getInstance()->displayBufferEnabled()) { + disableBufferAgain = true; { - std::lock_guard noRender(OswHal::getInstance()->drawLock); + std::lock_guard noRender(*OswUI::getInstance()->drawLock); OswHal::getInstance()->enableDisplayBuffer(); } sleep(1); // After this a new frame should be available! } + long contentLength = DISP_W * DISP_H * 3; + uint8_t buf[3 * DISP_W]; + this->m_webserver->client().write("HTTP/1.1 200 OK"); this->m_webserver->client().write((String("\r\nContent-Length: ") + String(contentLength)).c_str()); this->m_webserver->client().write("\r\nContent-Type: application/octet-stream"); @@ -252,6 +254,12 @@ void OswServiceTaskWebserver::handleScreenServer() { this->m_webserver->client().write(buf, 3 * DISP_W); yield(); } + + // Disable the buffer if it was inactive before + if(disableBufferAgain) { + std::lock_guard noRender(*OswUI::getInstance()->drawLock); + OswHal::getInstance()->disableDisplayBuffer(); + } #ifndef NDEBUG Serial.println(String(__FILE__) + ": Sent RAW screenshot!"); #endif From 5ced978d4bf5b0043c6cc3d5f9deb3371c2611dd Mon Sep 17 00:00:00 2001 From: simonmicro Date: Tue, 28 Jun 2022 16:05:58 +0200 Subject: [PATCH 071/116] Corrected accidential deadlock --- src/services/OswServiceTaskWebserver.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/services/OswServiceTaskWebserver.cpp b/src/services/OswServiceTaskWebserver.cpp index d0e74a050..c2b78a120 100644 --- a/src/services/OswServiceTaskWebserver.cpp +++ b/src/services/OswServiceTaskWebserver.cpp @@ -222,8 +222,6 @@ void OswServiceTaskWebserver::handleDataJson() { #ifdef RAW_SCREEN_SERVER void OswServiceTaskWebserver::handleScreenServer() { - std::lock_guard lock(*OswUI::getInstance()->drawLock); - // Note that we are using the screen buffer here, but is could be inactive right now -> activate and wait a while if it is bool disableBufferAgain = false; if(!OswHal::getInstance()->displayBufferEnabled()) { @@ -244,15 +242,19 @@ void OswServiceTaskWebserver::handleScreenServer() { this->m_webserver->client().write("\r\nConnection: close"); this->m_webserver->client().write("\r\n\r\n"); // empty line for header<->body delimiter - for (int y = 0; y < DISP_H; y++) { - for (int x = 0; x < DISP_W; x++) { - uint16_t rgb = OswHal::getInstance()->gfx()->getPixel(x, y); - buf[x * 3 + 0] = rgb565_red(rgb); - buf[x * 3 + 1] = rgb565_green(rgb); - buf[x * 3 + 2] = rgb565_blue(rgb); + // Fetch the screenshot itself + { + std::lock_guard noRender(*OswUI::getInstance()->drawLock); + for (int y = 0; y < DISP_H; y++) { + for (int x = 0; x < DISP_W; x++) { + uint16_t rgb = OswHal::getInstance()->gfx()->getPixel(x, y); + buf[x * 3 + 0] = rgb565_red(rgb); + buf[x * 3 + 1] = rgb565_green(rgb); + buf[x * 3 + 2] = rgb565_blue(rgb); + } + this->m_webserver->client().write(buf, 3 * DISP_W); + yield(); } - this->m_webserver->client().write(buf, 3 * DISP_W); - yield(); } // Disable the buffer if it was inactive before From eb8231df555963b156abe992c601be552e553d4a Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 28 Jun 2022 14:24:39 +0000 Subject: [PATCH 072/116] Applied formatting --- src/osw_config_keys.cpp | 12 ++++++------ src/services/OswServiceTaskMemMonitor.cpp | 2 +- src/services/OswServiceTaskWiFi.cpp | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/osw_config_keys.cpp b/src/osw_config_keys.cpp index 4089bed55..7450cd019 100644 --- a/src/osw_config_keys.cpp +++ b/src/osw_config_keys.cpp @@ -8,12 +8,12 @@ /** * !!!WARNING!!! - * + * * Never select the same label for two different keys (inside their constructor)! This will cause a * "feature" inside the webinterface to be activated, which will lead to an empty data.json to be saved. - * + * * There is no way to recover the users data after this. Be caureful! - * + * */ // Add your keys to this namespace (do not forget to also declare them inside the header) @@ -98,16 +98,16 @@ OswConfigKey* oswConfigKeys[] = { &OswConfigAllKeys::fallbackWifiSsid1st,&OswConfigAllKeys::fallbackWifiPass1st, &OswConfigAllKeys::fallbackWifiSsid2nd,&OswConfigAllKeys::fallbackWifiPass2nd, #ifdef OSW_FEATURE_WIFI_ONBOOT - &OswConfigAllKeys::wifiBootEnabled, + & OswConfigAllKeys::wifiBootEnabled, #endif - &OswConfigAllKeys::wifiAlwaysNTPEnabled, &OswConfigAllKeys::wifiAutoAP, + & OswConfigAllKeys::wifiAlwaysNTPEnabled, &OswConfigAllKeys::wifiAutoAP, #endif // display &OswConfigAllKeys::settingDisplayTimeout, &OswConfigAllKeys::settingDisplayBrightness, &OswConfigAllKeys::settingDisplayOverlays, &OswConfigAllKeys::settingDisplayOverlaysOnWatchScreen, &OswConfigAllKeys::settingDisplayDefaultWatchface, &OswConfigAllKeys::settingDisplayDualHourTick, #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 - &OswConfigAllKeys::settingDisplayStepsGoal, + & OswConfigAllKeys::settingDisplayStepsGoal, #endif // energy &OswConfigAllKeys::buttonToWakeEnabled, &OswConfigAllKeys::raiseToWakeEnabled, diff --git a/src/services/OswServiceTaskMemMonitor.cpp b/src/services/OswServiceTaskMemMonitor.cpp index bf261e216..a76a9b8c1 100644 --- a/src/services/OswServiceTaskMemMonitor.cpp +++ b/src/services/OswServiceTaskMemMonitor.cpp @@ -41,7 +41,7 @@ void OswServiceTaskMemMonitor::loop() { Serial.println(String(__FILE__) + ": Low memory condition! Activating countermeasures..."); if(!nowLowMemoryCondition and this->lowMemoryCondition) Serial.println(String(__FILE__) + ": Low memory condition resolved. Deactivating countermeasures..."); - + if(this->lowMemoryCondition != nowLowMemoryCondition) { OswUI* ui = OswUI::getInstance(); std::lock_guard noRender(*ui->drawLock); diff --git a/src/services/OswServiceTaskWiFi.cpp b/src/services/OswServiceTaskWiFi.cpp index f8338947a..d485be0ef 100644 --- a/src/services/OswServiceTaskWiFi.cpp +++ b/src/services/OswServiceTaskWiFi.cpp @@ -234,9 +234,9 @@ void OswServiceTaskWiFi::connectWiFi() { this->updateWiFiConfig(); this->selectCredentials(); if (this->m_clientPass.isEmpty()) { // If public Wi-Fi without a password - WiFi.begin(this->m_clientSSID.c_str()); + WiFi.begin(this->m_clientSSID.c_str()); } else { - WiFi.begin(this->m_clientSSID.c_str(), this->m_clientPass.c_str()); + WiFi.begin(this->m_clientSSID.c_str(), this->m_clientPass.c_str()); } if(!this->m_queuedNTPUpdate) this->m_queuedNTPUpdate = OswConfigAllKeys::wifiAlwaysNTPEnabled.get(); From c178fb2d1680c6a0e6657117ee52b5f8dcebfa9a Mon Sep 17 00:00:00 2001 From: simonmicro Date: Tue, 28 Jun 2022 16:41:25 +0200 Subject: [PATCH 073/116] Resync ESP if too async (>4 seconds) --- include/devices/esp32.h | 2 +- src/devices/esp32.cpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/devices/esp32.h b/include/devices/esp32.h index b7fadee10..d4f467510 100644 --- a/include/devices/esp32.h +++ b/include/devices/esp32.h @@ -10,7 +10,7 @@ class NativeESP32 : public OswTemperatureProvider, public OswTimeProvider { virtual ~NativeESP32() {}; virtual void setup() override; - virtual void update() override {}; + virtual void update() override; virtual void reset() override {}; virtual void stop() override {}; diff --git a/src/devices/esp32.cpp b/src/devices/esp32.cpp index c3cd67364..07bbc4872 100644 --- a/src/devices/esp32.cpp +++ b/src/devices/esp32.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -26,6 +27,21 @@ void OswDevices::NativeESP32::setup() { this->tempSensorIsBuiltIn = false; } +void OswDevices::NativeESP32::update() { + // The clock of the ESP32 sometimes drifts very rapidly. This checks for an other available provider + // and resyncs the ESP32 clock with it (as this is only way to control which time is reported by + // the function "time(nullptr);")... + time_t nowEsp = this->getUTCTime(); + time_t nowOther = OswHal::getInstance()->getUTCTime(); // In the future maybe respect priorities? + if(abs(nowEsp - nowOther) > 4) { + // Oh, the ESP is async again - resync! + struct timeval tv; + tv.tv_sec = nowOther; + tv.tv_usec = 0; + settimeofday(&tv, nullptr); + } +} + time_t OswDevices::NativeESP32::getUTCTime() { return time(nullptr); }; From 2d9384ed69ba354fe81a7487a306ae90ad75ebe1 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Tue, 28 Jun 2022 16:48:58 +0200 Subject: [PATCH 074/116] Added sync message --- src/devices/esp32.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/devices/esp32.cpp b/src/devices/esp32.cpp index 07bbc4872..0f55e5295 100644 --- a/src/devices/esp32.cpp +++ b/src/devices/esp32.cpp @@ -33,12 +33,16 @@ void OswDevices::NativeESP32::update() { // the function "time(nullptr);")... time_t nowEsp = this->getUTCTime(); time_t nowOther = OswHal::getInstance()->getUTCTime(); // In the future maybe respect priorities? - if(abs(nowEsp - nowOther) > 4) { + const time_t maxDiff = 4; + if(abs(nowEsp - nowOther) > maxDiff) { // Oh, the ESP is async again - resync! struct timeval tv; tv.tv_sec = nowOther; tv.tv_usec = 0; settimeofday(&tv, nullptr); +#ifndef NDEBUG + Serial.println(String(__FILE__) + ": Resynced internal ESP32 clock with other provider due to significant time difference (> " + String(maxDiff) + " seconds)."); +#endif } } From 83e519962a8554524dd49c226999f94af5a4eeff Mon Sep 17 00:00:00 2001 From: simonmicro Date: Tue, 28 Jun 2022 17:02:21 +0200 Subject: [PATCH 075/116] Faster reboot on release crashes --- src/main.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a69ae1d28..d5978c5d8 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,6 +62,12 @@ #include #endif +#ifndef NDEBUG + #define _MAIN_CRASH_SLEEP 10 +#else + #define _MAIN_CRASH_SLEEP 2 +#endif + OswHal* hal = nullptr; // OswAppRuntimeTest *runtimeTest = new OswAppRuntimeTest(); @@ -91,7 +97,7 @@ void setup() { hal->setup(false); } catch(const std::runtime_error& e) { Serial.println(String("CRITICAL ERROR AT BOOTUP: ") + e.what()); - sleep(10); + sleep(_MAIN_CRASH_SLEEP); ESP.restart(); } @@ -141,7 +147,7 @@ void loop() { } } catch(const std::runtime_error& e) { Serial.println(String("CRITICAL ERROR AT UPDATES: ") + e.what()); - sleep(10); + sleep(_MAIN_CRASH_SLEEP); ESP.restart(); } @@ -150,7 +156,7 @@ void loop() { OswUI::getInstance()->loop(mainAppSwitcher, mainAppIndex); } catch(const std::runtime_error& e) { Serial.println(String("CRITICAL ERROR AT APP: ") + e.what()); - sleep(10); + sleep(_MAIN_CRASH_SLEEP); ESP.restart(); } if (delayedAppInit) { From b53bcd117a44a46f77af07c275f4f4c406098953 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 28 Jun 2022 15:03:13 +0000 Subject: [PATCH 076/116] Applied formatting --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d5978c5d8..ea424259d 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -63,9 +63,9 @@ #endif #ifndef NDEBUG - #define _MAIN_CRASH_SLEEP 10 +#define _MAIN_CRASH_SLEEP 10 #else - #define _MAIN_CRASH_SLEEP 2 +#define _MAIN_CRASH_SLEEP 2 #endif OswHal* hal = nullptr; From 02165831bee2c113827be88a63d160f2969b86e8 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Wed, 22 Jun 2022 13:48:27 +0900 Subject: [PATCH 077/116] CI : add feature param resolve #241 --- .github/buildEverything.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/buildEverything.py b/.github/buildEverything.py index 6d2b4ea55..28c60f7b0 100755 --- a/.github/buildEverything.py +++ b/.github/buildEverything.py @@ -91,8 +91,13 @@ def doBuild(makeDebug): ap.add_argument("-l", "--support-language", type=str, required=True, help="# model language to compile. (Enter 'all' to compile all language packs.)") ap.add_argument("-m", "--support-model", type=str, required=True, help="# model type to compile. (Enter 'all' to compile all model packs.)") + ap.add_argument("-f", "--support-feature", type=str, required=False, default="", help="# feature to compile. (Enter a feature to compile.)") args = vars(ap.parse_args()) + if str(args["support_feature"]) != "": + logging.info('Setting flag ' + str(args["support_feature"]) + '...') + os.system('sed -i'' -r -e "/build_flags/a\ -D '+str(args["support_feature"])+'" platformio.ini') + #if you want all-language packs if args["support_language"] == "all" and args["support_model"] == "all": for lang in languages: From cb7d5fd9a55969ae95f13949b7bad3e3d28f8c67 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Thu, 23 Jun 2022 23:59:51 +0900 Subject: [PATCH 078/116] CI : refactoring set build flag part --- .github/buildEverything.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/buildEverything.py b/.github/buildEverything.py index 28c60f7b0..f1d5a7008 100755 --- a/.github/buildEverything.py +++ b/.github/buildEverything.py @@ -96,7 +96,17 @@ def doBuild(makeDebug): if str(args["support_feature"]) != "": logging.info('Setting flag ' + str(args["support_feature"]) + '...') - os.system('sed -i'' -r -e "/build_flags/a\ -D '+str(args["support_feature"])+'" platformio.ini') + # Setup build flag (using the config file via replacing, as platformio does not allow setting the property using Python) + configIn = open(pioConfig, 'r') + configStr = configIn.read() + configIn.close() + configStr, hitCount = re.subn('build_flags =','build_flags =\n -D '+str(args["support_feature"]),configStr) + if hitCount == 0: + logging.error('Error on setting build flag!') + exit(5) + configOut = open(pioConfig, 'w') + configOut.write(configStr) + configOut.close() #if you want all-language packs if args["support_language"] == "all" and args["support_model"] == "all": From cd7d153044a0d3904e42edc43e7d047ca8e815e9 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Wed, 29 Jun 2022 00:33:15 +0900 Subject: [PATCH 079/116] CI : remove firmware binary zip --- .github/workflows/test-FEATURE.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/test-FEATURE.yml b/.github/workflows/test-FEATURE.yml index d388d5b70..636c6d1f0 100644 --- a/.github/workflows/test-FEATURE.yml +++ b/.github/workflows/test-FEATURE.yml @@ -66,10 +66,4 @@ jobs: run: mv include/config.h.example include/config.h - name: Compile language ${{ matrix.language }} model ${{ matrix.model }} feature ${{ matrix.feature }} - run: python3 .github/buildEverything.py -l ${{ matrix.language }} -m ${{ matrix.model }} -f ${{ matrix.feature }} - - name: Upload firmware artifacts - uses: actions/upload-artifact@v2 - with: - name: firmwares - path: | - *.bin + run: python3 .github/buildEverything.py -l ${{ matrix.language }} -m ${{ matrix.model }} -f ${{ matrix.feature }} \ No newline at end of file From e54b7ebfcecf4301f24e06f7ee958cdc6bb70702 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Thu, 30 Jun 2022 03:11:34 +0900 Subject: [PATCH 080/116] CI : get-flag from docs --- .github/workflows/test-FEATURE.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/test-FEATURE.yml b/.github/workflows/test-FEATURE.yml index 636c6d1f0..4ef130d4c 100644 --- a/.github/workflows/test-FEATURE.yml +++ b/.github/workflows/test-FEATURE.yml @@ -16,19 +16,17 @@ jobs: submodules: recursive - id: get-flag run: | - echo "::set-output name=feature::$(F=$(cat feature-flag.md | grep "flag:" | sed -e 's/flag://' | tr ']\n' ' ');F=($F);jq --compact-output --null-input '$ARGS.positional' --args -- "${F[@]}")" + echo "::set-output name=feature::$(D=$(curl https://api.github.com/repos/Open-smartwatch/open-smartwatch.github.io/contents/docs/resources/firmware.md | jq -r ".content" | base64 --decode | grep -o '^-.*` |'); V=$(echo $D | tr '` |-' ' ');V=($V);jq --compact-output --null-input '$ARGS.positional' --args -- "${V[@]}")" - id: default_mod run: | echo "::set-output name=default_model::$(R=$(x=$(cat platformio.ini | grep "defau"); echo "${x:15}"); R=($R);jq --compact-output --null-input '$ARGS.positional' --args -- "${R[@]}")" - id: default_lang run: | echo "::set-output name=default_language::$(A=$(if [ -e include/locales/en-US.h ]; then s=$(ls include/locales/en-US.h); else s=$(ls include/locales/*.h -1 | head -1); fi; echo ${s:16:5});A=($A);jq --compact-output --null-input '$ARGS.positional' --args -- "${A[@]}")" - outputs: feature: ${{ steps.get-flag.outputs.feature }} default_model: ${{ steps.default_mod.outputs.default_model }} default_language: ${{ steps.default_lang.outputs.default_language }} - build-OSW: needs: Find-feature runs-on: ubuntu-latest @@ -61,9 +59,7 @@ jobs: uses: actions/setup-python@v2 - name: Install PlatformIO run: python -m pip install --upgrade pip && pip install --upgrade platformio - - name: Rename config run: mv include/config.h.example include/config.h - - name: Compile language ${{ matrix.language }} model ${{ matrix.model }} feature ${{ matrix.feature }} run: python3 .github/buildEverything.py -l ${{ matrix.language }} -m ${{ matrix.model }} -f ${{ matrix.feature }} \ No newline at end of file From 8dd78777da875e52e1f51c2b19dd53d0472bf8d3 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Sat, 2 Jul 2022 16:10:15 +0900 Subject: [PATCH 081/116] OswServiceTasks : no longer in use --- include/services/OswServiceTasks.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/services/OswServiceTasks.h b/include/services/OswServiceTasks.h index 5f7552d83..1a7fe660d 100644 --- a/include/services/OswServiceTasks.h +++ b/include/services/OswServiceTasks.h @@ -4,7 +4,6 @@ class OswServiceTaskBLECompanion; class OswServiceTaskExample; class OswServiceTaskMemMonitor; class OswServiceTaskWiFi; -class OswServiceTaskRawScreenServer; class OswServiceTaskWebserver; namespace OswServiceAllTasks { From 4d986a8aa8bcd353935b3a8af6fc1f127e72ec6e Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Sun, 3 Jul 2022 12:26:44 +0900 Subject: [PATCH 082/116] OswServiceTasks : add webserver libraries in OSW_FEATURE_WIFI --- src/services/OswServiceTasks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/OswServiceTasks.cpp b/src/services/OswServiceTasks.cpp index 9e3df9873..4b588864a 100644 --- a/src/services/OswServiceTasks.cpp +++ b/src/services/OswServiceTasks.cpp @@ -6,9 +6,9 @@ #include "services/OswServiceTaskMemMonitor.h" #ifdef OSW_FEATURE_WIFI #include "services/OswServiceTaskWiFi.h" +#include "services/OswServiceTaskWebserver.h" #endif #include "osw_util.h" -#include "services/OswServiceTaskWebserver.h" namespace OswServiceAllTasks { // OswServiceTaskExample example; From 572458e46935ef11707df35a058c1d7672218ca7 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Sun, 3 Jul 2022 12:31:03 +0900 Subject: [PATCH 083/116] OswServiceTaskMemMonitor : add OSW_FEATURE_WIFI --- src/services/OswServiceTaskMemMonitor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/services/OswServiceTaskMemMonitor.cpp b/src/services/OswServiceTaskMemMonitor.cpp index a76a9b8c1..fc04ae794 100644 --- a/src/services/OswServiceTaskMemMonitor.cpp +++ b/src/services/OswServiceTaskMemMonitor.cpp @@ -4,7 +4,9 @@ #include "osw_ui.h" #include "services/OswServiceManager.h" #include "services/OswServiceTasks.h" +#ifdef OSW_FEATURE_WIFI #include "services/OswServiceTaskWebserver.h" +#endif #include "services/OswServiceTaskBLECompanion.h" void OswServiceTaskMemMonitor::setup() { @@ -26,10 +28,12 @@ void OswServiceTaskMemMonitor::loop() { // Check for a low memory condition and try to free system resources to help out bool nowLowMemoryCondition = false; +#ifdef OSW_FEATURE_WIFI if(OswServiceAllTasks::webserver.webserverActive()) { if(this->lowMemoryCondition or ESP.getFreeHeap() < 100000) // Keep low memory or enable if less than 100kb available nowLowMemoryCondition = true; } +#endif #if SERVICE_BLE_COMPANION == 1 if(OswServiceAllTasks::bleCompanion.isRunning()) { if(this->lowMemoryCondition or ESP.getFreeHeap() < 400000) // Keep low memory or enable if less than 400kb available From 6f9e2ee924d3090d01b28945fa24d37f9be85a7e Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Sun, 3 Jul 2022 12:35:01 +0900 Subject: [PATCH 084/116] OswServiceTasks : update OSW_FEATURE_WIFI --- include/services/OswServiceTasks.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/services/OswServiceTasks.h b/include/services/OswServiceTasks.h index 1a7fe660d..cc098fce4 100644 --- a/include/services/OswServiceTasks.h +++ b/include/services/OswServiceTasks.h @@ -3,16 +3,19 @@ class OswServiceTaskBLECompanion; class OswServiceTaskExample; class OswServiceTaskMemMonitor; +#ifdef OSW_FEATURE_WIFI class OswServiceTaskWiFi; class OswServiceTaskWebserver; - +#endif namespace OswServiceAllTasks { #if SERVICE_BLE_COMPANION == 1 extern OswServiceTaskBLECompanion bleCompanion; #endif //extern OswServiceTaskExample example; +#ifdef OSW_FEATURE_WIFI extern OswServiceTaskWiFi wifi; extern OswServiceTaskWebserver webserver; +#endif extern OswServiceTaskMemMonitor memory; } From e0347af299aff97f08da90794e764685091a1b2b Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Tue, 5 Jul 2022 02:38:05 +0900 Subject: [PATCH 085/116] OswServiceTaskMemMonitor : change libraries pre-processing --- include/services/OswServiceTaskMemMonitor.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/services/OswServiceTaskMemMonitor.h b/include/services/OswServiceTaskMemMonitor.h index 4e34ce09e..48a29b55e 100644 --- a/include/services/OswServiceTaskMemMonitor.h +++ b/include/services/OswServiceTaskMemMonitor.h @@ -1,5 +1,4 @@ -#ifndef OSW_SERVICE_TASKMEMMONITOR_H -#define OSW_SERVICE_TASKMEMMONITOR_H +#pragma once #include "osw_service.h" @@ -18,6 +17,4 @@ class OswServiceTaskMemMonitor : public OswServiceTask { unsigned core1high; unsigned heapHigh; bool lowMemoryCondition = false; -}; - -#endif \ No newline at end of file +}; \ No newline at end of file From d3a3ba1cd21855850e0f8ff67892748071a08829 Mon Sep 17 00:00:00 2001 From: Lavoisier Date: Tue, 5 Jul 2022 03:01:42 +0900 Subject: [PATCH 086/116] Apps/tools : set pre-processing OSW_FEATURE_STATS_STEPS --- include/apps/tools/OswAppKcalStats.h | 6 +++++- include/apps/tools/OswAppStepStats.h | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/apps/tools/OswAppKcalStats.h b/include/apps/tools/OswAppKcalStats.h index de8e9731f..338d1d1a1 100644 --- a/include/apps/tools/OswAppKcalStats.h +++ b/include/apps/tools/OswAppKcalStats.h @@ -1,3 +1,5 @@ +#ifdef OSW_FEATURE_STATS_STEPS + #pragma once #include @@ -19,4 +21,6 @@ class OswAppKcalStats : public OswApp { void drawCurvedChart(); void showCurvedChart(); OswUI* ui; -}; \ No newline at end of file +}; + +#endif \ No newline at end of file diff --git a/include/apps/tools/OswAppStepStats.h b/include/apps/tools/OswAppStepStats.h index fd4874887..60d376ae2 100644 --- a/include/apps/tools/OswAppStepStats.h +++ b/include/apps/tools/OswAppStepStats.h @@ -1,3 +1,5 @@ +#ifdef OSW_FEATURE_STATS_STEPS + #pragma once #include @@ -18,4 +20,6 @@ class OswAppStepStats : public OswApp { void showStickChart(); void drawChart(); OswUI* ui; -}; \ No newline at end of file +}; + +#endif \ No newline at end of file From d364554fc968bd72ae5dec13fe75e13ad58f3f58 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Wed, 6 Jul 2022 07:32:50 +0900 Subject: [PATCH 087/116] OswAppPrintDebug : add flag for pre-processing - closes #255 --- include/apps/tools/OswAppPrintDebug.h | 4 +++- src/apps/tools/OswAppPrintDebug.cpp | 2 ++ src/main.cpp | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/apps/tools/OswAppPrintDebug.h b/include/apps/tools/OswAppPrintDebug.h index 07ec0f03c..a9b5e69f3 100644 --- a/include/apps/tools/OswAppPrintDebug.h +++ b/include/apps/tools/OswAppPrintDebug.h @@ -1,3 +1,4 @@ +#ifndef NDEBUG #pragma once #include @@ -15,4 +16,5 @@ class OswAppPrintDebug : public OswApp { uint8_t y = 32; uint8_t x = 52; void printStatus(const char* setting, const char* value); -}; \ No newline at end of file +}; +#endif \ No newline at end of file diff --git a/src/apps/tools/OswAppPrintDebug.cpp b/src/apps/tools/OswAppPrintDebug.cpp index f02d407ef..42474de17 100644 --- a/src/apps/tools/OswAppPrintDebug.cpp +++ b/src/apps/tools/OswAppPrintDebug.cpp @@ -1,3 +1,4 @@ +#ifndef NDEBUG #include "./apps/tools/OswAppPrintDebug.h" @@ -133,3 +134,4 @@ void OswAppPrintDebug::stop() { OswHal::getInstance()->gpsBackupMode(); #endif } +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index ea424259d..4f099a3f9 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,7 +34,9 @@ #include "./apps/main/stopwatch.h" #include "./apps/main/switcher.h" #include "./apps/tools/button_test.h" +#ifndef NDEBUG #include "./apps/tools/OswAppPrintDebug.h" +#endif #include "./apps/tools/OswAppTimeConfig.h" #include "./apps/tools/water_level.h" #include "./apps/tools/OswAppFitnessStats.h" From e350e3c227c53a25496732573ab26d38ff4aa2a8 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Sun, 10 Jul 2022 23:19:47 +0900 Subject: [PATCH 088/116] Common : fixed typo --- include/hal/environment.h | 2 +- include/osw_config_keys.h | 4 ++-- include/osw_hal.h | 2 +- src/apps/_experiments/dnatilt.cpp | 2 +- src/apps/tools/OswAppPrintDebug.cpp | 2 +- src/hal/buttons.cpp | 2 +- src/osw_config.cpp | 4 ++-- src/osw_hal.cpp | 2 +- src/services/OswServiceTaskBLECompanion.cpp | 2 +- src/services/OswServiceTaskMemMonitor.cpp | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/hal/environment.h b/include/hal/environment.h index ac4f7336d..92e46bfd8 100644 --- a/include/hal/environment.h +++ b/include/hal/environment.h @@ -10,7 +10,7 @@ #if OSW_PLATFORM_ENVIRONMENT == 1 class OswHal::Environment { public: - void updateProviders(); // Retreive all environment sensors + void updateProviders(); // Retrieve all environment sensors void reset(); // Reset all data on environment sensors #if OSW_PLATFORM_ENVIRONMENT_TEMPERATURE == 1 diff --git a/include/osw_config_keys.h b/include/osw_config_keys.h index 748018c78..08879c10b 100644 --- a/include/osw_config_keys.h +++ b/include/osw_config_keys.h @@ -8,7 +8,7 @@ #include "osw_config.h" -// Forward delcarations: All OswConfigKey types +// Forward declarations: All OswConfigKey types class OswConfigKeyString; class OswConfigKeyPassword; class OswConfigKeyDropDown; @@ -97,7 +97,7 @@ class OswConfigKey { friend OswConfig; }; -// This holds a refrence to all compiled config keys, so we can e.g. iterate over them +// This holds a reference to all compiled config keys, so we can e.g. iterate over them extern const unsigned char oswConfigKeysCount; extern OswConfigKey* oswConfigKeys[]; diff --git a/include/osw_hal.h b/include/osw_hal.h index aa4359c03..8c7f93640 100644 --- a/include/osw_hal.h +++ b/include/osw_hal.h @@ -208,7 +208,7 @@ class OswHal { OswTimeProvider* timeProvider = nullptr; unsigned long _screenOnSince; unsigned long _screenOffSince; - // array of avaialble buttons for iteration (e.g. handling) + // array of available buttons for iteration (e.g. handling) bool _btnLastState[NUM_BUTTONS]; bool _btnIsDown[NUM_BUTTONS]; bool _btnGoneUp[NUM_BUTTONS]; diff --git a/src/apps/_experiments/dnatilt.cpp b/src/apps/_experiments/dnatilt.cpp index fd98b9521..eba88c437 100644 --- a/src/apps/_experiments/dnatilt.cpp +++ b/src/apps/_experiments/dnatilt.cpp @@ -45,7 +45,7 @@ void OswAppDNATilt::loop() { /* THIS IS NOW MANAGED BY THE WIFI SERVICE. The get() method is still a NON-STATIC method of MiniWiFi and therfore currently unusable. - Then you need this code working, please contact the author of the MiniWiFi lib or extend it youself. + Then you need this code working, please contact the author of the MiniWiFi lib or extend it yourself. if (hal->getAccelerationX() > 250) { hal->getWiFi()->get("http://192.168.1.54/api/ladder/hue/decr", httpGetBuffer, HTTP_GET_BUF_LEN); diff --git a/src/apps/tools/OswAppPrintDebug.cpp b/src/apps/tools/OswAppPrintDebug.cpp index 42474de17..3cc8b6c25 100644 --- a/src/apps/tools/OswAppPrintDebug.cpp +++ b/src/apps/tools/OswAppPrintDebug.cpp @@ -92,7 +92,7 @@ void OswAppPrintDebug::loop() { hal->isSDMounted() ? String(String((uint)(hal->sdCardSize() / (1024 * 1024))) + " MB").c_str() : "N/A"); printStatus("GPS:", hal->hasGPS() ? "OK" : "missing"); - printStatus("Sattelites: ", String(hal->gpsNumSatellites()).c_str()); + printStatus("Satellites: ", String(hal->gpsNumSatellites()).c_str()); printStatus("Latitude", String(hal->gpsLat()).c_str()); printStatus("Longitude", String(hal->gpsLon()).c_str()); diff --git a/src/hal/buttons.cpp b/src/hal/buttons.cpp index 1a9b3f75f..39b51cc8b 100644 --- a/src/hal/buttons.cpp +++ b/src/hal/buttons.cpp @@ -62,7 +62,7 @@ void OswHal::checkButtons(void) { _btnIsDownMillis[i] = millis(); } - // check if the button hass been down long enough + // check if the button has been down long enough _btnLongPress[i] = millis() > _btnIsDownMillis[i] + DEFAULTLAUNCHER_LONG_PRESS && _btnIsDown[i] == true; // store current button state diff --git a/src/osw_config.cpp b/src/osw_config.cpp index ccd43382a..7bfc6c942 100644 --- a/src/osw_config.cpp +++ b/src/osw_config.cpp @@ -63,14 +63,14 @@ void OswConfig::disableWrite() { }; /** - * Get the amount of sytem boots since the last config wipe. + * Get the amount of system boots since the last config wipe. */ int OswConfig::getBootCount() { return this->prefs.getInt(this->configBootCntKey); } /** - * Resets this namespace by formatting the nvs parition. + * Resets this namespace by formatting the nvs partition. */ void OswConfig::reset() { this->prefs.end(); diff --git a/src/osw_hal.cpp b/src/osw_hal.cpp index 170c600f9..b9a4e3ddc 100644 --- a/src/osw_hal.cpp +++ b/src/osw_hal.cpp @@ -29,7 +29,7 @@ OswHal::~OswHal() { void OswHal::setup(bool fromLightSleep) { if(!fromLightSleep) { { - // To ensure following steps are performed after the static init phase, they must be perfromed inside the setup() + // To ensure following steps are performed after the static init phase, they must be performed inside the setup() this->devices = new Devices(); this->updateTimeProvider(); #if OSW_PLATFORM_ENVIRONMENT == 1 diff --git a/src/services/OswServiceTaskBLECompanion.cpp b/src/services/OswServiceTaskBLECompanion.cpp index 612cccd78..a82a8147f 100644 --- a/src/services/OswServiceTaskBLECompanion.cpp +++ b/src/services/OswServiceTaskBLECompanion.cpp @@ -47,7 +47,7 @@ class NotificationCallback: public BLECharacteristicCallbacks { NotificationDetails details {uid, app, contents}; - //Notify our client about the new notificaiton + // Notify our client about the new notification if (companion->notificationCallback) { companion->notificationCallback(details); } diff --git a/src/services/OswServiceTaskMemMonitor.cpp b/src/services/OswServiceTaskMemMonitor.cpp index fc04ae794..1db6d74b4 100644 --- a/src/services/OswServiceTaskMemMonitor.cpp +++ b/src/services/OswServiceTaskMemMonitor.cpp @@ -78,7 +78,7 @@ void OswServiceTaskMemMonitor::updateLoopTaskStats() { } /** - * Send a overview regarding the current stack watermarks (core 0&1), heap watermarks and heap useage to serial + * Send a overview regarding the current stack watermarks (core 0&1), heap watermarks and heap ussage to serial */ void OswServiceTaskMemMonitor::printStats() { #ifndef NDEBUG From 87a2628bf2c07460ce92b082d676d1eb447e955f Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Mon, 11 Jul 2022 12:48:27 +0900 Subject: [PATCH 089/116] README : update build, debugging, troubleshooting description --- Readme.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 4e3239329..9b87c121b 100644 --- a/Readme.md +++ b/Readme.md @@ -12,7 +12,11 @@ $ git clone --recurse-submodules https://github.com/Open-Smartwatch/open-smartwatch-os.git ``` -## build (Visual Studio Code) +## build + +The `master` branch is a stable version and the `develop` branch is a beta version. Recommended that you upload the `master` branch. + +### Visual Studio Code Open the cloned repo in VSCode: @@ -22,7 +26,7 @@ $ code open-smartwatch-os And rename file `include/config.h.example` to `include/config.h` and adapt the values according to your requirements and press `F5` to build it. -## build (CLI) +### CLI You can instead go to the repo folder with your terminal and run @@ -38,6 +42,14 @@ $ pio run -e pico32_GPS_EDITION -t upload Depending on the watch model. +## Debugging(CLI) + +If you want to print out the log for debugging, following command: + +``` +$ pio device monitor +``` + ## Creating Screen Shots of your Apps @@ -72,6 +84,9 @@ $ ./createScreenshot.sh ``` * The captured file can be found in the `screenshot/` folder inside the `open-smartwatch-os` directory. ## Troubleshooting + +For more information on troubleshooting, see [Wiki](https://open-smartwatch.github.io/resources/firmware/#troubleshooting). + ### Arduino_TFT.h: No such file or directory You did not clone the repository with the `--recursive-submodules` flag. From ea4240222f90c8b849587e7381d87fca0c45f70c Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Mon, 11 Jul 2022 14:34:52 +0900 Subject: [PATCH 090/116] CONTRIBUTING : add CONTRIBUTING docs --- CONTRIBUTING.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..177a763c4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,25 @@ +# How to contribute to the Open-smartwatch + +When the develop branch is ahead of the master and the develop branch is in the stabilization phase, it periodically merges the develop branch into the master. + +In order to contribute new or updated documentation, you must first create a GitHub account and fork the original repository to your own account. You can make changes, save them in your repository, then make a pull request against this repository. The pull request will appear in the repository where it can be assessed by the maintainers, copy edited, and if appropriate, merged with the official repository. + +Unless you are opening a pull request which will only make small corrections, for instance to correct a typo, you are more likely to get traction for your changes if you open an issue first to discuss the proposed changes. + +NOTE: If you want to send a pull request, please work based on the develop branch + +If you are reading this page, you are possibly interested in contributing to our project. We have a very active (and friendly) developer group and would love to have the help! Possible ways you can help: + +* Testing the code +* Filing issues on github, when you see a problem (or adding detail to existing issues that effect you) +* Fixing issues +* Adding new features +* Reviewing existing pull requests, and notifying the maintainer if it passes your code review. + +## How to make a good bug report + +Submit according to the bug report form. Attach the debug log if necessary. [Read more](https://open-smartwatch.github.io/howto/contribute/#how-to-open-an-issue) + +## Submitting patches + +Please see our [wiki](https://open-smartwatch.github.io/howto/contribute/) article. From 961b6133abbd7841d1cfd1c6324d3394ce66c954 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Mon, 11 Jul 2022 20:49:00 +0200 Subject: [PATCH 091/116] Correction of English grammar and sentences --- CONTRIBUTING.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 177a763c4..ef6b375d2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,25 +1,26 @@ -# How to contribute to the Open-smartwatch +# How to contribute to Open-smartwatch -When the develop branch is ahead of the master and the develop branch is in the stabilization phase, it periodically merges the develop branch into the master. +In case the `develop` branch is ahead of the `master` branch and the `develop` branch is stabile enough, we periodically merge it into the `master`. -In order to contribute new or updated documentation, you must first create a GitHub account and fork the original repository to your own account. You can make changes, save them in your repository, then make a pull request against this repository. The pull request will appear in the repository where it can be assessed by the maintainers, copy edited, and if appropriate, merged with the official repository. +In order to contribute new or updated documentation, you must first create a GitHub account and fork the original repository to your own account. You can make changes, save them in your repository and then create a pull request against this repository. -Unless you are opening a pull request which will only make small corrections, for instance to correct a typo, you are more likely to get traction for your changes if you open an issue first to discuss the proposed changes. +Unless you are opening a pull request which only makes small corrections (for instance correcting a typo), you are more likely to get traction for your changes if you open an issue first to discuss the proposed changes. -NOTE: If you want to send a pull request, please work based on the develop branch +**IMPORTANT** If you want to create a pull request, please work based on the `develop` branch - so we don't have to rebase it... -If you are reading this page, you are possibly interested in contributing to our project. We have a very active (and friendly) developer group and would love to have the help! Possible ways you can help: +If you are reading this page, you are possibly interested in contributing to our project 😄 . We have an active (and friendly) developer group and would love to get your help! Some common ways you can support us are: * Testing the code -* Filing issues on github, when you see a problem (or adding detail to existing issues that effect you) -* Fixing issues +* Filing issues on GitHub, if you see a problem (or adding detail to existing issues that effect you) +* Fixing issues 😁 * Adding new features -* Reviewing existing pull requests, and notifying the maintainer if it passes your code review. +* Reviewing existing pull requests and possibly also contributing to them. +* Translation. Always a good idea... ## How to make a good bug report -Submit according to the bug report form. Attach the debug log if necessary. [Read more](https://open-smartwatch.github.io/howto/contribute/#how-to-open-an-issue) +Submit according to the bug report form. Attach the debug log if necessary. [Read more here!](https://open-smartwatch.github.io/howto/contribute/#how-to-open-an-issue) ## Submitting patches -Please see our [wiki](https://open-smartwatch.github.io/howto/contribute/) article. +Please also see our [wiki](https://open-smartwatch.github.io/howto/contribute/) article for that. From d07a17c58aa9fe277f7f997f20657294f0c94767 Mon Sep 17 00:00:00 2001 From: Romain Coumans Date: Sun, 10 Jul 2022 01:19:28 +0200 Subject: [PATCH 092/116] Allow setting custom long press button timeouts --- include/config_defaults.h | 10 +++++++++- include/osw_hal.h | 1 - src/apps/main/stopwatch.cpp | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/config_defaults.h b/include/config_defaults.h index dc9dfff12..989b2ed89 100644 --- a/include/config_defaults.h +++ b/include/config_defaults.h @@ -154,14 +154,19 @@ #define THEME_DANGER_COLOR rgb888(255, 56, 96) #endif +// Set the long press time to switch between apps. +#ifndef DEFAULTLAUNCHER_LONG_PRESS +#define DEFAULTLAUNCHER_LONG_PRESS 1000 +#endif + // The following settings are configureable later on using the web ui, you can still set the defaults here. -// Daylight saving time offset in hours. E.g. 0.5 = 30 min #ifndef CONFIG_DATE_FORMAT // possibilities: "yyyy.mm.dd" or "mm/dd/yyyy" #define CONFIG_DATE_FORMAT "mm/dd/yyyy" #endif +// Daylight saving time offset in hours. E.g. 0.5 = 30 min #ifndef CONFIG_DAYLIGHTOFFSET #define CONFIG_DAYLIGHTOFFSET 0 #endif @@ -196,6 +201,9 @@ #ifndef TOOL_STOPWATCH #define TOOL_STOPWATCH 1 #endif +#ifndef TOOL_STOPWATCH_BTN_TIMEOUT +#define TOOL_STOPWATCH_BTN_TIMEOUT 1800 +#endif #ifndef TOOL_WATERLEVEL #define TOOL_WATERLEVEL 1 #endif diff --git a/include/osw_hal.h b/include/osw_hal.h index 8c7f93640..ac8cef24d 100644 --- a/include/osw_hal.h +++ b/include/osw_hal.h @@ -20,7 +20,6 @@ #define ERR_SD_MISSING 1 #define ERR_SD_MOUNT_FAILED 2 -#define DEFAULTLAUNCHER_LONG_PRESS 1000 #define NUM_BUTTONS 3 // enum for user space button handling enum Button { BUTTON_1 = 0, BUTTON_2 = 1, BUTTON_3 = 2 }; diff --git a/src/apps/main/stopwatch.cpp b/src/apps/main/stopwatch.cpp index ad072632f..815b6d9b7 100644 --- a/src/apps/main/stopwatch.cpp +++ b/src/apps/main/stopwatch.cpp @@ -42,7 +42,7 @@ void OswAppStopWatch::loop() { } long totalTime = diff + sumPaused; - long btnTimeout = 1800; + long btnTimeout = TOOL_STOPWATCH_BTN_TIMEOUT; long btnDown = 0; if(running) { if(hal->btnHasGoneDown(BUTTON_2)) { From 930d5eff98e95ad1ef37381d9e6bba2a89802376 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Mon, 11 Jul 2022 21:36:28 +0200 Subject: [PATCH 093/116] Added two settings for button press time (long+sleep) --- include/apps/main/switcher.h | 2 ++ include/config_defaults.h | 9 +++++++-- include/osw_config_keys.h | 2 ++ src/apps/main/switcher.cpp | 18 +++++++++--------- src/hal/buttons.cpp | 2 +- src/osw_config_keys.cpp | 3 +++ 6 files changed, 24 insertions(+), 12 deletions(-) diff --git a/include/apps/main/switcher.h b/include/apps/main/switcher.h index 3b17fb128..f7ef299b8 100644 --- a/include/apps/main/switcher.h +++ b/include/apps/main/switcher.h @@ -43,6 +43,8 @@ class OswAppSwitcher : public OswApp { bool _doSleep = false; bool _doSwitch = false; long appOnScreenSince = 0; + short _timeForLongPress = APPSWITCHER_LONG_PRESS; + short _timeForSleepPress = APPSWITCHER_SLEEP_TIMEOUT; }; #endif diff --git a/include/config_defaults.h b/include/config_defaults.h index 989b2ed89..17d946b9b 100644 --- a/include/config_defaults.h +++ b/include/config_defaults.h @@ -155,8 +155,13 @@ #endif // Set the long press time to switch between apps. -#ifndef DEFAULTLAUNCHER_LONG_PRESS -#define DEFAULTLAUNCHER_LONG_PRESS 1000 +#ifndef APPSWITCHER_LONG_PRESS +#define APPSWITCHER_LONG_PRESS 800 +#endif + +// Hold it that much longer to send the watch to sleep... +#ifndef APPSWITCHER_SLEEP_TIMEOUT +#define APPSWITCHER_SLEEP_TIMEOUT 1000 #endif // The following settings are configureable later on using the web ui, you can still set the defaults here. diff --git a/include/osw_config_keys.h b/include/osw_config_keys.h index 08879c10b..ab75b8426 100644 --- a/include/osw_config_keys.h +++ b/include/osw_config_keys.h @@ -45,6 +45,8 @@ extern OswConfigKeyRGB themeInfoColor; extern OswConfigKeyRGB themeSuccessColor; extern OswConfigKeyRGB themeWarningColor; extern OswConfigKeyRGB themeDangerColor; +extern OswConfigKeyShort appSwitcherLongPress; +extern OswConfigKeyShort appSwitcherSleepPress; extern OswConfigKeyShort settingDisplayTimeout; extern OswConfigKeyShort settingDisplayBrightness; extern OswConfigKeyBool settingDisplayOverlays; diff --git a/src/apps/main/switcher.cpp b/src/apps/main/switcher.cpp index eeb3304fe..30644ea83 100644 --- a/src/apps/main/switcher.cpp +++ b/src/apps/main/switcher.cpp @@ -1,14 +1,14 @@ #include "./apps/main/switcher.h" -#define SLEEP_TIMOUT 1000 - void OswAppSwitcher::setup() { appOnScreenSince = millis(); if (*_rtcAppIndex >= _appCount) { *_rtcAppIndex = 0; } _apps[*_rtcAppIndex]->setup(); + this->_timeForLongPress = OswConfigAllKeys::appSwitcherLongPress.get(); + this->_timeForSleepPress = OswConfigAllKeys::appSwitcherSleepPress.get(); } void OswAppSwitcher::loop() { @@ -20,7 +20,7 @@ void OswAppSwitcher::loop() { } // if we enable sending the watch to sleep by clicking (really really) long enough - if (_enableSleep && hal->btnIsDownSince(_btn) > DEFAULTLAUNCHER_LONG_PRESS + SLEEP_TIMOUT) { + if (_enableSleep and hal->btnIsDownSince(_btn) > this->_timeForLongPress + this->_timeForSleepPress) { // remember we need to sleep once the button goes up _doSleep = true; } @@ -28,7 +28,7 @@ void OswAppSwitcher::loop() { // detect switch action depending on mode switch (_type) { case LONG_PRESS: - if (hal->btnIsDownSince(_btn) > DEFAULTLAUNCHER_LONG_PRESS) { + if (hal->btnIsDownSince(_btn) > this->_timeForLongPress) { _doSwitch = true; } break; @@ -118,14 +118,14 @@ void OswAppSwitcher::loop() { switch (_type) { case LONG_PRESS: // long press has the hollow square that fills (draws around short press) - if (hal->btnIsDownSince(_btn) > DEFAULTLAUNCHER_LONG_PRESS) { + if (hal->btnIsDownSince(_btn) > this->_timeForLongPress) { // draw a large frame hal->gfx()->fillCircle(btnX, btnY, 20, OswUI::getInstance()->getSuccessColor()); } else { uint8_t progress = 0; - if (hal->btnIsDownSince(_btn) > DEFAULTLAUNCHER_LONG_PRESS / 2) { - progress = (hal->btnIsDownSince(_btn) - (DEFAULTLAUNCHER_LONG_PRESS / 2)) / - ((DEFAULTLAUNCHER_LONG_PRESS / 2) / 255.0); + if (hal->btnIsDownSince(_btn) > this->_timeForLongPress / 2) { + progress = (hal->btnIsDownSince(_btn) - (this->_timeForLongPress / 2)) / + ((this->_timeForLongPress / 2) / 255.0); } hal->gfx()->drawArc(btnX, btnY, progressOffset, progressOffset + (progress / 255.0) * 180, progress / 4, 20, 3, OswUI::getInstance()->getForegroundColor()); @@ -136,7 +136,7 @@ void OswAppSwitcher::loop() { hal->gfx()->fillCircle(btnX, btnY, 10, OswUI::getInstance()->getSuccessColor()); } - if (_enableSleep && hal->btnIsDownSince(_btn) > DEFAULTLAUNCHER_LONG_PRESS + SLEEP_TIMOUT) { + if (_enableSleep and hal->btnIsDownSince(_btn) > this->_timeForLongPress + this->_timeForSleepPress) { // draw half moon hal->gfx()->fillCircle(btnX, btnY, 9, OswUI::getInstance()->getForegroundDimmedColor()); hal->gfx()->fillCircle(btnX, btnY, 8, OswUI::getInstance()->getBackgroundColor()); diff --git a/src/hal/buttons.cpp b/src/hal/buttons.cpp index 39b51cc8b..fd6bd9579 100644 --- a/src/hal/buttons.cpp +++ b/src/hal/buttons.cpp @@ -63,7 +63,7 @@ void OswHal::checkButtons(void) { } // check if the button has been down long enough - _btnLongPress[i] = millis() > _btnIsDownMillis[i] + DEFAULTLAUNCHER_LONG_PRESS && _btnIsDown[i] == true; + _btnLongPress[i] = _btnIsDown[i] == true and (millis() > _btnIsDownMillis[i] + OswConfigAllKeys::appSwitcherLongPress.get()); // store current button state _btnLastState[i] = _btnIsDown[i]; diff --git a/src/osw_config_keys.cpp b/src/osw_config_keys.cpp index 7450cd019..2b53df824 100644 --- a/src/osw_config_keys.cpp +++ b/src/osw_config_keys.cpp @@ -47,6 +47,8 @@ OswConfigKeyBool settingDisplayDualHourTick("h2", "Display", "Display Dual-Time #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 OswConfigKeyBool settingDisplayStepsGoal("g1", "Display", "Display Steps Goal", "Show goal steps", true); #endif +OswConfigKeyShort appSwitcherLongPress("d4", "Display", "App Switcher Long Press", "in ms", APPSWITCHER_LONG_PRESS); +OswConfigKeyShort appSwitcherSleepPress("d5", "Display", "App Switcher Sleep Press", "in ms", APPSWITCHER_SLEEP_TIMEOUT); OswConfigKeyBool raiseToWakeEnabled("s5", "Power", "Raise/Tilt to Wake", "Enables Raise to Wake", WAKE_FROM_RAISE); OswConfigKeyShort raiseToWakeSensitivity("s6", "Power", "Raise to Wake Sensitivity", @@ -106,6 +108,7 @@ OswConfigKey* oswConfigKeys[] = { &OswConfigAllKeys::settingDisplayTimeout, &OswConfigAllKeys::settingDisplayBrightness, &OswConfigAllKeys::settingDisplayOverlays, &OswConfigAllKeys::settingDisplayOverlaysOnWatchScreen, &OswConfigAllKeys::settingDisplayDefaultWatchface, &OswConfigAllKeys::settingDisplayDualHourTick, + &OswConfigAllKeys::appSwitcherLongPress, &OswConfigAllKeys::appSwitcherSleepPress, #if OSW_PLATFORM_ENVIRONMENT_ACCELEROMETER == 1 & OswConfigAllKeys::settingDisplayStepsGoal, #endif From 1381a0406507a0260dfe94e6432bf5416e6f0070 Mon Sep 17 00:00:00 2001 From: simonmicro Date: Tue, 12 Jul 2022 12:29:23 +0200 Subject: [PATCH 094/116] Minor code cleanup --- src/devices/esp32.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/devices/esp32.cpp b/src/devices/esp32.cpp index 0f55e5295..ac9c350db 100644 --- a/src/devices/esp32.cpp +++ b/src/devices/esp32.cpp @@ -36,10 +36,7 @@ void OswDevices::NativeESP32::update() { const time_t maxDiff = 4; if(abs(nowEsp - nowOther) > maxDiff) { // Oh, the ESP is async again - resync! - struct timeval tv; - tv.tv_sec = nowOther; - tv.tv_usec = 0; - settimeofday(&tv, nullptr); + this->setUTCTime(nowOther); #ifndef NDEBUG Serial.println(String(__FILE__) + ": Resynced internal ESP32 clock with other provider due to significant time difference (> " + String(maxDiff) + " seconds)."); #endif @@ -51,7 +48,10 @@ time_t OswDevices::NativeESP32::getUTCTime() { }; void OswDevices::NativeESP32::setUTCTime(const time_t& epoch) { - struct timeval now = { .tv_sec = epoch }; + struct timeval now = { + .tv_sec = epoch, + .tv_usec = 0 + }; settimeofday(&now, nullptr); }; From 16f39eddba3f7f516bfe3e09317c7247b3f2fad6 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Wed, 13 Jul 2022 22:54:20 +0900 Subject: [PATCH 095/116] Stopwatch : add overall-time measurement --- include/apps/main/stopwatch.h | 1 + src/apps/main/stopwatch.cpp | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/apps/main/stopwatch.h b/include/apps/main/stopwatch.h index 575579836..8a6d51439 100644 --- a/include/apps/main/stopwatch.h +++ b/include/apps/main/stopwatch.h @@ -33,6 +33,7 @@ class OswAppStopWatch : public OswApp { unsigned char lapNum = 0; long lastLapTime = 0; long laps[maxLaps] = {0}; + long overall[maxLaps] = {0}; char lapPages = 0; char lapPage = 0; }; diff --git a/src/apps/main/stopwatch.cpp b/src/apps/main/stopwatch.cpp index 815b6d9b7..bb48c98e6 100644 --- a/src/apps/main/stopwatch.cpp +++ b/src/apps/main/stopwatch.cpp @@ -16,6 +16,7 @@ RTC_DATA_ATTR bool running = false; RTC_DATA_ATTR bool reset = true; RTC_DATA_ATTR long sumPaused = 0; RTC_DATA_ATTR long stepsOffset = 0; +RTC_DATA_ATTR bool overallTime = true; void OswAppStopWatch::setup() {} @@ -49,13 +50,17 @@ void OswAppStopWatch::loop() { addLap(totalTime); } } else { - if(hal->btnIsDown(BUTTON_2)) { + if (hal->btnHasGoneDown(BUTTON_2)) { + overallTime = !overallTime; + } + if(hal->btnIsDown(BUTTON_2)) { // Reset btnDown = hal->btnIsDownSince(BUTTON_2); if(btnDown > btnTimeout) { diff = 0; sumPaused = 0; for(unsigned char l = 0; l < maxLaps; l++) { laps[l] = 0; + overall[l] = 0; } lapNum = 0; lapPages = 0; @@ -73,12 +78,12 @@ void OswAppStopWatch::loop() { } } - if(lapNum > 0) { + if(lapNum > 0) { // First laps-time on the little bar drawTime(totalTime, DISP_H/4, 3); hal->gfx()->drawThickLine(DISP_W*1/4, DISP_H/2, DISP_W*3/4, DISP_H/2, 2, ui->getPrimaryColor()); hal->gfx()->drawThickLine(DISP_W*10/12, DISP_H/2, DISP_W*11/12, DISP_H/2, 2, ui->getPrimaryColor()); } else { - drawTime(totalTime, DISP_H/2, 4); + drawTime(totalTime, DISP_H/2, 4); // not laps-time (Big font) } drawLaps(); drawPageIndicator(); @@ -96,6 +101,7 @@ void OswAppStopWatch::loop() { void OswAppStopWatch::addLap(long totalTime) { if(lapNum < maxLaps) { + overall[lapNum] = totalTime; laps[lapNum] = totalTime - lastLapTime; lapNum ++; lapPages = (lapNum-2) / lapsPerPage + 1; @@ -123,12 +129,18 @@ void OswAppStopWatch::drawTime(long totalTime, long y, char size) { void OswAppStopWatch::drawLaps() { if(lapNum > 0) { - drawTime(laps[lapNum - 1], (DISP_H / 4) + 40, 2); + if(overallTime) + drawTime(overall[lapNum - 1], (DISP_H / 4) + 40, 2); + else + drawTime(laps[lapNum - 1], (DISP_H / 4) + 40, 2); } char moved = lapsPerPage * lapPage; for(char i = 0; i < lapsPerPage && (i+1) + moved < lapNum; i++) { long y = (DISP_H / 4) + ((i+1) * 20) + 60; - drawTime(laps[lapNum - 1 - moved - (i + 1)], y, 2); + if (overallTime) + drawTime(overall[lapNum - 1 - moved - (i + 1)], y, 2); + else + drawTime(laps[lapNum - 1 - moved - (i + 1)], y, 2); } } From dc6387a24c2ee69aac964e6849b0734881875d76 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Thu, 14 Jul 2022 21:51:48 +0900 Subject: [PATCH 096/116] Dist-stats : add Distance stats --- include/apps/tools/OswAppDistStats.h | 26 ++++++++ src/apps/tools/OswAppDistStats.cpp | 88 ++++++++++++++++++++++++++++ src/main.cpp | 2 + 3 files changed, 116 insertions(+) create mode 100644 include/apps/tools/OswAppDistStats.h create mode 100644 src/apps/tools/OswAppDistStats.cpp diff --git a/include/apps/tools/OswAppDistStats.h b/include/apps/tools/OswAppDistStats.h new file mode 100644 index 000000000..37f3d5d57 --- /dev/null +++ b/include/apps/tools/OswAppDistStats.h @@ -0,0 +1,26 @@ +#ifdef OSW_FEATURE_STATS_STEPS + +#pragma once + +#include +#include +#include "osw_app.h" + +class OswAppDistStats : public OswApp { + public: + OswAppDistStats(void) { + ui = OswUI::getInstance(); + }; + virtual void setup() override; + virtual void loop() override; + virtual void stop() override; + ~OswAppDistStats() {}; + + private: + void showStickChart(); + void drawChart(); + OswUI* ui; + uint32_t cursorPos; // WeekDay position +}; + +#endif \ No newline at end of file diff --git a/src/apps/tools/OswAppDistStats.cpp b/src/apps/tools/OswAppDistStats.cpp new file mode 100644 index 000000000..716acb8c1 --- /dev/null +++ b/src/apps/tools/OswAppDistStats.cpp @@ -0,0 +1,88 @@ +#ifdef OSW_FEATURE_STATS_STEPS + +#include "./apps/tools/OswAppDistStats.h" +#include "./apps/watchfaces/OswAppWatchfaceFitness.h" + +#include +#include +#include +#include + +void OswAppDistStats::drawChart() { + OswHal* hal = OswHal::getInstance(); + uint8_t chartStickHeight = 55; + uint8_t interval = 20; + uint16_t goalValue = OswConfigAllKeys::distPerDay.get(); + + uint32_t weekDay = 0; + uint32_t dayOfMonth = 0; + hal->getLocalDate(&dayOfMonth, &weekDay); + + for (uint8_t index = 0; index < 7; index++) { + uint32_t weekDayStep = OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(index)); + uint16_t chartStickValue = ((float)(weekDayStep > goalValue ? goalValue : weekDayStep) / goalValue) * chartStickHeight; + + uint16_t barColor = OswConfigAllKeys::distPerDay.get() <= weekDayStep ? ui->getSuccessColor() : changeColor(ui->getSuccessColor(),2.85); + + chartStickValue = chartStickValue < 2 ? 0 : chartStickValue; + + if (index == cursorPos) { + hal->gfx()->drawThickTick(60 + index * interval, 147, 0, chartStickHeight, 0, 5, ui->getForegroundColor()); + } + hal->gfx()->drawThickTick(60 + index * interval, 147, 0, chartStickValue, 0, 3, barColor, true); + } +} + +void OswAppDistStats::showStickChart() { + OswHal* hal = OswHal::getInstance(); + + hal->gfx()->setTextMiddleAligned(); + hal->gfx()->setTextCenterAligned(); + + hal->gfx()->setTextSize(2); + hal->gfx()->setTextCursor(DISP_H / 2, 60); + hal->gfx()->setTextColor(ui->getForegroundColor()); + hal->gfx()->print(LANG_DISTSTATS_TITLE); + + OswAppDistStats::drawChart(); + + uint8_t coord_x = 30; + + hal->gfx()->drawThickTick(coord_x, 150, 0, DISP_W - (coord_x * 2), 90, 2, ui->getPrimaryColor()); + + hal->gfx()->setTextSize(1); + hal->gfx()->setTextCenterAligned(); + hal->gfx()->setTextBottomAligned(); + hal->gfx()->setTextCursor(120, 170); + hal->gfx()->print(hal->getLocalWeekday(&cursorPos)); + hal->gfx()->setTextCursor(120, 190); + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(cursorPos,true))) ); // lastweek(before 7 day) + hal->gfx()->setTextCursor(120, 215); + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()) / 7)+String("/")+String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()))); // Avg/Total + hal->gfx()->setTextSize(2); + hal->gfx()->setTextCursor(120, 205); + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(cursorPos)) + String(" m"))); // Big font Fitness value +} + +void OswAppDistStats::setup() { + OswHal *hal = OswHal::getInstance(); + uint32_t weekDay = 0; + uint32_t dayOfMonth = 0; + hal->getLocalDate(&dayOfMonth, &weekDay); + cursorPos = weekDay; +} +void OswAppDistStats::loop() { + OswHal *hal = OswHal::getInstance(); + if (hal->btnHasGoneDown(BUTTON_3)) { + this->cursorPos = this->cursorPos + 1 > 6 ? 6 : this->cursorPos + 1; + } + if (hal->btnHasGoneDown(BUTTON_2)) { + this->cursorPos = this->cursorPos - 1 < 0 ? 0 : this->cursorPos - 1; + } + + showStickChart(); + hal->requestFlush(); +} + +void OswAppDistStats::stop() {} +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 4f099a3f9..063e493ba 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,6 +43,7 @@ #ifdef OSW_FEATURE_STATS_STEPS #include "./apps/tools/OswAppKcalStats.h" #include "./apps/tools/OswAppStepStats.h" +#include "./apps/tools/OswAppDistStats.h" #endif #include "./apps/watchfaces/OswAppWatchface.h" #include "./apps/watchfaces/OswAppWatchfaceDigital.h" @@ -181,6 +182,7 @@ void loop() { #ifdef OSW_FEATURE_STATS_STEPS fitnessAppSwitcher.registerApp(new OswAppStepStats()); fitnessAppSwitcher.registerApp(new OswAppKcalStats()); + fitnessAppSwitcher.registerApp(new OswAppDistStats()); #endif fitnessAppSwitcher.registerApp(new OswAppFitnessStats()); fitnessAppSwitcher.paginationEnable(); From 1781ec20d1af927502aca8a44de75991c7073ab8 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Thu, 14 Jul 2022 21:52:36 +0900 Subject: [PATCH 097/116] Language : add Distance stats title --- include/locales/en-US.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/locales/en-US.h b/include/locales/en-US.h index ada92be17..2e9462f55 100644 --- a/include/locales/en-US.h +++ b/include/locales/en-US.h @@ -41,11 +41,14 @@ #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" + // App: Kcal Statistics -#define LANG_KCAL_TITLE "Kcal stats" -#define LANG_KCAL_AVG "Avg" -#define LANG_KCAL_TODAY "Today" -#define LANG_KCAL_STEP "Step" +#define LANG_KCALSTATS_TITLE "Kcal stats" +#define LANG_KCALSTATS_AVG "Avg" +#define LANG_KCALSTATS_TODAY "Today" +#define LANG_KCALSTATS_STEP "Step" // Weekdays #define LANG_MONDAY "Monday" From 95c2890721e13d072e92381a4adf39520f0a11c6 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Thu, 14 Jul 2022 21:59:07 +0900 Subject: [PATCH 098/116] OswAppKcalStats : rename Kcal part --- src/apps/tools/OswAppKcalStats.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/apps/tools/OswAppKcalStats.cpp b/src/apps/tools/OswAppKcalStats.cpp index 373896282..b4b5a3847 100644 --- a/src/apps/tools/OswAppKcalStats.cpp +++ b/src/apps/tools/OswAppKcalStats.cpp @@ -65,7 +65,7 @@ void OswAppKcalStats::showCurvedChart() { hal->gfx()->setTextSize(2); hal->gfx()->setTextCursor(DISP_H / 2, 60); hal->gfx()->setTextColor(ui->getForegroundColor()); - hal->gfx()->print(LANG_KCAL_TITLE); + hal->gfx()->print(LANG_KCALSTATS_TITLE); OswAppKcalStats::drawCurvedChart(); @@ -80,7 +80,7 @@ void OswAppKcalStats::showCurvedChart() { hal->gfx()->setTextBottomAligned(); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextCursor(80, 165); - hal->gfx()->print(LANG_KCAL_AVG); + hal->gfx()->print(LANG_KCALSTATS_AVG); hal->gfx()->setTextCursor(160, 165); hal->gfx()->print(hal->getLocalWeekday(&wDay)); hal->gfx()->setTextRightAligned(); @@ -94,7 +94,7 @@ void OswAppKcalStats::showCurvedChart() { hal->gfx()->setTextCursor(DISP_W / 2 + 7, 185); hal->gfx()->print(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(wDay))+String(" m")); hal->gfx()->setTextCursor(DISP_W / 2 + 7, 195); - hal->gfx()->print(hal->environment->getStepsOnDay(wDay) + String(" ") + String(LANG_KCAL_STEP)); + hal->gfx()->print(hal->environment->getStepsOnDay(wDay) + String(" ") + String(LANG_KCALSTATS_STEP)); hal->gfx()->setTextCursor(DISP_W / 2 + 7, 205); hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDay(wDay))+String(" kcal")); } From 4d6bd5a08d77f26f7e475f8f0eb5af66d1fcc220 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Thu, 14 Jul 2022 22:22:29 +0900 Subject: [PATCH 099/116] Fitness-info : refactoring data style --- include/apps/tools/OswAppStepStats.h | 3 +- src/apps/tools/OswAppKcalStats.cpp | 27 ++++---------- src/apps/tools/OswAppStepStats.cpp | 55 +++++++++++++++------------- 3 files changed, 40 insertions(+), 45 deletions(-) diff --git a/include/apps/tools/OswAppStepStats.h b/include/apps/tools/OswAppStepStats.h index 60d376ae2..505796ef4 100644 --- a/include/apps/tools/OswAppStepStats.h +++ b/include/apps/tools/OswAppStepStats.h @@ -19,7 +19,8 @@ class OswAppStepStats : public OswApp { private: void showStickChart(); void drawChart(); - OswUI* ui; + uint32_t cursorPos; + OswUI *ui; }; #endif \ No newline at end of file diff --git a/src/apps/tools/OswAppKcalStats.cpp b/src/apps/tools/OswAppKcalStats.cpp index b4b5a3847..9bfdc450a 100644 --- a/src/apps/tools/OswAppKcalStats.cpp +++ b/src/apps/tools/OswAppKcalStats.cpp @@ -71,32 +71,21 @@ void OswAppKcalStats::showCurvedChart() { uint8_t coordX = 30; hal->gfx()->drawThickTick(coordX, 150, 0, 240 - (coordX * 2), 90, 2, ui->getPrimaryColor()); - hal->gfx()->drawLine(DISP_W / 2, 165, 120, 220, ui->getPrimaryColor()); // Data info uint32_t wDay = findCursorWeekDay(this->cursorPos); hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextBottomAligned(); - hal->gfx()->setTextCenterAligned(); - hal->gfx()->setTextCursor(80, 165); - hal->gfx()->print(LANG_KCALSTATS_AVG); - hal->gfx()->setTextCursor(160, 165); + hal->gfx()->setTextCursor(120, 170); hal->gfx()->print(hal->getLocalWeekday(&wDay)); - hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor(DISP_W / 2 - 7, 185); - hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()) / 7 )); - hal->gfx()->setTextCursor(DISP_W / 2 - 7, 195); - hal->gfx()->print(hal->environment->getStepsTotalWeek()/7); - hal->gfx()->setTextCursor(DISP_W / 2 - 7, 205); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek())/7); - hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(DISP_W / 2 + 7, 185); - hal->gfx()->print(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(wDay))+String(" m")); - hal->gfx()->setTextCursor(DISP_W / 2 + 7, 195); - hal->gfx()->print(hal->environment->getStepsOnDay(wDay) + String(" ") + String(LANG_KCALSTATS_STEP)); - hal->gfx()->setTextCursor(DISP_W / 2 + 7, 205); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDay(wDay))+String(" kcal")); + hal->gfx()->setTextCursor(120, 190); + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDay(wDay, true)))); // lastweek(before 7 day) + hal->gfx()->setTextCursor(120, 215); + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek()) / 7) + String("/") + String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek()))); // Avg/Total + hal->gfx()->setTextSize(2); + hal->gfx()->setTextCursor(120, 205); + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDay(wDay)) + String(" Kcal"))); // Big font Fitness value } void OswAppKcalStats::setup() {} diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index 58d94a6fb..faca74bf5 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -26,7 +26,7 @@ void OswAppStepStats::drawChart() { chartStickValue = chartStickValue < 2 ? 0 : chartStickValue; - if (index == weekDay) { + if (index == cursorPos) { hal->gfx()->drawThickTick(60 + index * interval, 147, 0, chartStickHeight, 0, 5, ui->getForegroundColor()); } hal->gfx()->drawThickTick(60 + index * interval, 147, 0, chartStickValue, 0, 3, barColor, true); @@ -49,35 +49,40 @@ void OswAppStepStats::showStickChart() { uint8_t coord_x = 30; hal->gfx()->drawThickTick(coord_x, 150, 0, DISP_W - (coord_x * 2), 90, 2, ui->getPrimaryColor()); - hal->gfx()->drawLine(DISP_W / 2, 165, DISP_W / 2, 220, ui->getPrimaryColor()); // long front - + hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextBottomAligned(); - hal->gfx()->setTextCursor(80, 165); - hal->gfx()->print(LANG_STEPSTATS_TOTAL); - hal->gfx()->setTextCursor(160, 165); - hal->gfx()->print(LANG_STEPSTATS_TODAY); - - hal->gfx()->setTextRightAligned(); - hal->gfx()->setTextCursor(DISP_W / 2 - 7, 185); - hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()))); - hal->gfx()->setTextCursor(DISP_W / 2 - 7, 195); - hal->gfx()->print(hal->environment->getStepsTotalWeek() ); - hal->gfx()->setTextCursor(DISP_W / 2 - 7, 205); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek()) ); - hal->gfx()->setTextLeftAligned(); - hal->gfx()->setTextCursor(DISP_W / 2 + 7, 185); - hal->gfx()->print(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsToday())+String(" m")); - hal->gfx()->setTextCursor(DISP_W / 2 + 7, 195); - hal->gfx()->print(hal->environment->getStepsToday() +String(" ")+ String(LANG_STEPSTATS_STEP)); - hal->gfx()->setTextCursor(DISP_W / 2 + 7, 205); - hal->gfx()->print(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsToday())+String(" kcal")); + hal->gfx()->setTextCursor(120, 170); + hal->gfx()->print(hal->getLocalWeekday(&cursorPos)); + hal->gfx()->setTextCursor(120, 190); + hal->gfx()->print(String(hal->environment->getStepsOnDay(cursorPos, true))); // lastweek(before 7 day) + hal->gfx()->setTextCursor(120, 215); + hal->gfx()->print(String(hal->environment->getStepsTotalWeek() / 7) + String("/") + String(hal->environment->getStepsTotalWeek())); // Avg/Total + hal->gfx()->setTextSize(2); + hal->gfx()->setTextCursor(120, 205); + hal->gfx()->print(String(hal->environment->getStepsOnDay(cursorPos))); // Big font Fitness value } -void OswAppStepStats::setup() {} -void OswAppStepStats::loop() { - OswHal* hal = OswHal::getInstance(); +void OswAppStepStats::setup() +{ + OswHal *hal = OswHal::getInstance(); + uint32_t weekDay = 0; + uint32_t dayOfMonth = 0; + hal->getLocalDate(&dayOfMonth, &weekDay); + cursorPos = weekDay; +} +void OswAppStepStats::loop() +{ + OswHal *hal = OswHal::getInstance(); + if (hal->btnHasGoneDown(BUTTON_3)) + { + this->cursorPos = this->cursorPos + 1 > 6 ? 6 : this->cursorPos + 1; + } + if (hal->btnHasGoneDown(BUTTON_2)) + { + this->cursorPos = this->cursorPos - 1 < 0 ? 0 : this->cursorPos - 1; + } showStickChart(); hal->requestFlush(); } From 3a08a61baf2eb2f4068a7fc0d201fb2354b64014 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Thu, 14 Jul 2022 23:46:05 +0900 Subject: [PATCH 100/116] Stats-cursor : fixed cursor range bug --- include/apps/tools/OswAppDistStats.h | 2 +- include/apps/tools/OswAppStepStats.h | 2 +- src/apps/tools/OswAppDistStats.cpp | 8 ++++---- src/apps/tools/OswAppStepStats.cpp | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/apps/tools/OswAppDistStats.h b/include/apps/tools/OswAppDistStats.h index 37f3d5d57..7987cf037 100644 --- a/include/apps/tools/OswAppDistStats.h +++ b/include/apps/tools/OswAppDistStats.h @@ -20,7 +20,7 @@ class OswAppDistStats : public OswApp { void showStickChart(); void drawChart(); OswUI* ui; - uint32_t cursorPos; // WeekDay position + int32_t cursorPos = 0; // WeekDay position }; #endif \ No newline at end of file diff --git a/include/apps/tools/OswAppStepStats.h b/include/apps/tools/OswAppStepStats.h index 505796ef4..b39aca7d2 100644 --- a/include/apps/tools/OswAppStepStats.h +++ b/include/apps/tools/OswAppStepStats.h @@ -19,7 +19,7 @@ class OswAppStepStats : public OswApp { private: void showStickChart(); void drawChart(); - uint32_t cursorPos; + int32_t cursorPos=0; OswUI *ui; }; diff --git a/src/apps/tools/OswAppDistStats.cpp b/src/apps/tools/OswAppDistStats.cpp index 716acb8c1..ce9d32100 100644 --- a/src/apps/tools/OswAppDistStats.cpp +++ b/src/apps/tools/OswAppDistStats.cpp @@ -49,19 +49,19 @@ void OswAppDistStats::showStickChart() { uint8_t coord_x = 30; hal->gfx()->drawThickTick(coord_x, 150, 0, DISP_W - (coord_x * 2), 90, 2, ui->getPrimaryColor()); - + uint32_t tmpCursor = cursorPos; hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextBottomAligned(); hal->gfx()->setTextCursor(120, 170); - hal->gfx()->print(hal->getLocalWeekday(&cursorPos)); + hal->gfx()->print(hal->getLocalWeekday(&tmpCursor)); hal->gfx()->setTextCursor(120, 190); - hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(cursorPos,true))) ); // lastweek(before 7 day) + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(tmpCursor,true))) ); // lastweek(before 7 day) hal->gfx()->setTextCursor(120, 215); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()) / 7)+String("/")+String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()))); // Avg/Total hal->gfx()->setTextSize(2); hal->gfx()->setTextCursor(120, 205); - hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(cursorPos)) + String(" m"))); // Big font Fitness value + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(tmpCursor)) + String(" m"))); // Big font Fitness value } void OswAppDistStats::setup() { diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index faca74bf5..250aea97f 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -49,19 +49,19 @@ void OswAppStepStats::showStickChart() { uint8_t coord_x = 30; hal->gfx()->drawThickTick(coord_x, 150, 0, DISP_W - (coord_x * 2), 90, 2, ui->getPrimaryColor()); - + uint32_t tmpCursor = cursorPos; hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextBottomAligned(); hal->gfx()->setTextCursor(120, 170); - hal->gfx()->print(hal->getLocalWeekday(&cursorPos)); + hal->gfx()->print(hal->getLocalWeekday(&tmpCursor)); hal->gfx()->setTextCursor(120, 190); - hal->gfx()->print(String(hal->environment->getStepsOnDay(cursorPos, true))); // lastweek(before 7 day) + hal->gfx()->print(String(hal->environment->getStepsOnDay(tmpCursor, true))); // lastweek(before 7 day) hal->gfx()->setTextCursor(120, 215); hal->gfx()->print(String(hal->environment->getStepsTotalWeek() / 7) + String("/") + String(hal->environment->getStepsTotalWeek())); // Avg/Total hal->gfx()->setTextSize(2); hal->gfx()->setTextCursor(120, 205); - hal->gfx()->print(String(hal->environment->getStepsOnDay(cursorPos))); // Big font Fitness value + hal->gfx()->print(String(hal->environment->getStepsOnDay(tmpCursor))); // Big font Fitness value } void OswAppStepStats::setup() From 3b2dbd3e6c34c7f0647a6e9ece79015f60fb57d1 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Thu, 14 Jul 2022 23:52:00 +0900 Subject: [PATCH 101/116] Language : update translation --- include/locales/cs-CZ.h | 11 +++++++---- include/locales/de-DE.h | 11 +++++++---- include/locales/fr-FR.h | 11 +++++++---- include/locales/hu-HU.h | 11 +++++++---- include/locales/it-IT.h | 11 +++++++---- include/locales/ko-KR.h | 11 +++++++---- 6 files changed, 42 insertions(+), 24 deletions(-) diff --git a/include/locales/cs-CZ.h b/include/locales/cs-CZ.h index b73a7ff37..299b41201 100644 --- a/include/locales/cs-CZ.h +++ b/include/locales/cs-CZ.h @@ -41,11 +41,14 @@ #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" + // App: Kcal Statistics -#define LANG_KCAL_TITLE "Kcal stats" -#define LANG_KCAL_AVG "Avg" -#define LANG_KCAL_TODAY "Today" -#define LANG_KCAL_STEP "Step" +#define LANG_KCALSTATS_TITLE "Kcal stats" +#define LANG_KCALSTATS_AVG "Avg" +#define LANG_KCALSTATS_TODAY "Today" +#define LANG_KCALSTATS_STEP "Step" // Weekdays #define LANG_MONDAY "Pondeli" diff --git a/include/locales/de-DE.h b/include/locales/de-DE.h index 579746974..8d1e00662 100644 --- a/include/locales/de-DE.h +++ b/include/locales/de-DE.h @@ -41,11 +41,14 @@ #define LANG_FITNESS_DISTANCE "Distanz" #define LANG_FITNESS_TOTAL "Insgesamt" +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" + // App: Kcal Statistics -#define LANG_KCAL_TITLE "Kcal-Statistik" -#define LANG_KCAL_AVG "AVG" -#define LANG_KCAL_TODAY "Heute" -#define LANG_KCAL_STEP "Schritte" +#define LANG_KCALSTATS_TITLE "Kcal-Statistik" +#define LANG_KCALSTATS_AVG "AVG" +#define LANG_KCALSTATS_TODAY "Heute" +#define LANG_KCALSTATS_STEP "Schritte" // Weekdays #define LANG_MONDAY "Montag" diff --git a/include/locales/fr-FR.h b/include/locales/fr-FR.h index 963c7e1bd..c63524c8f 100644 --- a/include/locales/fr-FR.h +++ b/include/locales/fr-FR.h @@ -41,11 +41,14 @@ #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" + // App: Kcal Statistics -#define LANG_KCAL_TITLE "Kcal stats" -#define LANG_KCAL_AVG "Avg" -#define LANG_KCAL_TODAY "Today" -#define LANG_KCAL_STEP "Step" +#define LANG_KCALSTATS_TITLE "Kcal stats" +#define LANG_KCALSTATS_AVG "Avg" +#define LANG_KCALSTATS_TODAY "Today" +#define LANG_KCALSTATS_STEP "Step" // Weekdays #define LANG_MONDAY "Lundi" diff --git a/include/locales/hu-HU.h b/include/locales/hu-HU.h index ab13a1dc4..9a3dbb81e 100644 --- a/include/locales/hu-HU.h +++ b/include/locales/hu-HU.h @@ -41,11 +41,14 @@ #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" + // App: Kcal Statistics -#define LANG_KCAL_TITLE "Kcal stats" -#define LANG_KCAL_AVG "Avg" -#define LANG_KCAL_TODAY "Today" -#define LANG_KCAL_STEP "Step" +#define LANG_KCALSTATS_TITLE "Kcal stats" +#define LANG_KCALSTATS_AVG "Avg" +#define LANG_KCALSTATS_TODAY "Today" +#define LANG_KCALSTATS_STEP "Step" // Weekdays #define LANG_MONDAY "Hétfő" diff --git a/include/locales/it-IT.h b/include/locales/it-IT.h index 0addaeb1d..6c1ee0ebe 100644 --- a/include/locales/it-IT.h +++ b/include/locales/it-IT.h @@ -41,11 +41,14 @@ #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" + // App: Kcal Statistics -#define LANG_KCAL_TITLE "Kcal stats" -#define LANG_KCAL_AVG "Avg" -#define LANG_KCAL_TODAY "Today" -#define LANG_KCAL_STEP "Step" +#define LANG_KCALSTATS_TITLE "Kcal stats" +#define LANG_KCALSTATS_AVG "Avg" +#define LANG_KCALSTATS_TODAY "Today" +#define LANG_KCALSTATS_STEP "Step" // Weekdays #define LANG_MONDAY "Lunedì" diff --git a/include/locales/ko-KR.h b/include/locales/ko-KR.h index 96c874d16..57a056fec 100644 --- a/include/locales/ko-KR.h +++ b/include/locales/ko-KR.h @@ -54,11 +54,14 @@ #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" + // App: Kcal Statistics -#define LANG_KCAL_TITLE "Kcal stats" -#define LANG_KCAL_AVG "Avg" -#define LANG_KCAL_TODAY "Today" -#define LANG_KCAL_STEP "Step" +#define LANG_KCALSTATS_TITLE "Kcal stats" +#define LANG_KCALSTATS_AVG "Avg" +#define LANG_KCALSTATS_TODAY "Today" +#define LANG_KCALSTATS_STEP "Step" // Weekdays #define LANG_MONDAY "월요일" From 0f054ec0d7152fc2c1ec96754db91f100597e6f5 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Fri, 15 Jul 2022 00:13:18 +0900 Subject: [PATCH 102/116] Stats coord : refactoring hardcode --- src/apps/tools/OswAppDistStats.cpp | 8 ++++---- src/apps/tools/OswAppKcalStats.cpp | 8 ++++---- src/apps/tools/OswAppStepStats.cpp | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/apps/tools/OswAppDistStats.cpp b/src/apps/tools/OswAppDistStats.cpp index ce9d32100..1ad7f8fd7 100644 --- a/src/apps/tools/OswAppDistStats.cpp +++ b/src/apps/tools/OswAppDistStats.cpp @@ -53,14 +53,14 @@ void OswAppDistStats::showStickChart() { hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextBottomAligned(); - hal->gfx()->setTextCursor(120, 170); + hal->gfx()->setTextCursor(DISP_W/2, 170); hal->gfx()->print(hal->getLocalWeekday(&tmpCursor)); - hal->gfx()->setTextCursor(120, 190); + hal->gfx()->setTextCursor(DISP_W/2, 190); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(tmpCursor,true))) ); // lastweek(before 7 day) - hal->gfx()->setTextCursor(120, 215); + hal->gfx()->setTextCursor(DISP_W/2, 215); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()) / 7)+String("/")+String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()))); // Avg/Total hal->gfx()->setTextSize(2); - hal->gfx()->setTextCursor(120, 205); + hal->gfx()->setTextCursor(DISP_W/2, 205); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(tmpCursor)) + String(" m"))); // Big font Fitness value } diff --git a/src/apps/tools/OswAppKcalStats.cpp b/src/apps/tools/OswAppKcalStats.cpp index 9bfdc450a..9aa0a75be 100644 --- a/src/apps/tools/OswAppKcalStats.cpp +++ b/src/apps/tools/OswAppKcalStats.cpp @@ -77,14 +77,14 @@ void OswAppKcalStats::showCurvedChart() { hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextBottomAligned(); - hal->gfx()->setTextCursor(120, 170); + hal->gfx()->setTextCursor(DISP_W/2, 170); hal->gfx()->print(hal->getLocalWeekday(&wDay)); - hal->gfx()->setTextCursor(120, 190); + hal->gfx()->setTextCursor(DISP_W/2, 190); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDay(wDay, true)))); // lastweek(before 7 day) - hal->gfx()->setTextCursor(120, 215); + hal->gfx()->setTextCursor(DISP_W/2, 215); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek()) / 7) + String("/") + String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek()))); // Avg/Total hal->gfx()->setTextSize(2); - hal->gfx()->setTextCursor(120, 205); + hal->gfx()->setTextCursor(DISP_W/2, 205); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDay(wDay)) + String(" Kcal"))); // Big font Fitness value } diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index 250aea97f..4b145b652 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -53,14 +53,14 @@ void OswAppStepStats::showStickChart() { hal->gfx()->setTextSize(1); hal->gfx()->setTextCenterAligned(); hal->gfx()->setTextBottomAligned(); - hal->gfx()->setTextCursor(120, 170); + hal->gfx()->setTextCursor(DISP_W/2, 170); hal->gfx()->print(hal->getLocalWeekday(&tmpCursor)); - hal->gfx()->setTextCursor(120, 190); + hal->gfx()->setTextCursor(DISP_W/2, 190); hal->gfx()->print(String(hal->environment->getStepsOnDay(tmpCursor, true))); // lastweek(before 7 day) - hal->gfx()->setTextCursor(120, 215); + hal->gfx()->setTextCursor(DISP_W/2, 215); hal->gfx()->print(String(hal->environment->getStepsTotalWeek() / 7) + String("/") + String(hal->environment->getStepsTotalWeek())); // Avg/Total hal->gfx()->setTextSize(2); - hal->gfx()->setTextCursor(120, 205); + hal->gfx()->setTextCursor(DISP_W/2, 205); hal->gfx()->print(String(hal->environment->getStepsOnDay(tmpCursor))); // Big font Fitness value } From 7b953b3932394ee22fa5ebd3b272e1d870060ddd Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Fri, 15 Jul 2022 02:26:05 +0900 Subject: [PATCH 103/116] Dist-stats : rename variable --- src/apps/tools/OswAppDistStats.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/apps/tools/OswAppDistStats.cpp b/src/apps/tools/OswAppDistStats.cpp index 1ad7f8fd7..5e8f47f17 100644 --- a/src/apps/tools/OswAppDistStats.cpp +++ b/src/apps/tools/OswAppDistStats.cpp @@ -19,10 +19,10 @@ void OswAppDistStats::drawChart() { hal->getLocalDate(&dayOfMonth, &weekDay); for (uint8_t index = 0; index < 7; index++) { - uint32_t weekDayStep = OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(index)); - uint16_t chartStickValue = ((float)(weekDayStep > goalValue ? goalValue : weekDayStep) / goalValue) * chartStickHeight; + uint32_t weekDayDist = OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(index)); + uint16_t chartStickValue = ((float)(weekDayDist > goalValue ? goalValue : weekDayDist) / goalValue) * chartStickHeight; - uint16_t barColor = OswConfigAllKeys::distPerDay.get() <= weekDayStep ? ui->getSuccessColor() : changeColor(ui->getSuccessColor(),2.85); + uint16_t barColor = OswConfigAllKeys::distPerDay.get() <= weekDayDist ? ui->getSuccessColor() : changeColor(ui->getSuccessColor(),2.85); chartStickValue = chartStickValue < 2 ? 0 : chartStickValue; From 8b96945080c9e9985c72b49d98cc92d1f61ae5cf Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 14 Jul 2022 17:45:57 +0000 Subject: [PATCH 104/116] Applied formatting --- include/apps/tools/OswAppStepStats.h | 2 +- src/apps/tools/OswAppDistStats.cpp | 4 ++-- src/apps/tools/OswAppStepStats.cpp | 16 ++++++---------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/include/apps/tools/OswAppStepStats.h b/include/apps/tools/OswAppStepStats.h index b39aca7d2..b6929e84c 100644 --- a/include/apps/tools/OswAppStepStats.h +++ b/include/apps/tools/OswAppStepStats.h @@ -20,7 +20,7 @@ class OswAppStepStats : public OswApp { void showStickChart(); void drawChart(); int32_t cursorPos=0; - OswUI *ui; + OswUI* ui; }; #endif \ No newline at end of file diff --git a/src/apps/tools/OswAppDistStats.cpp b/src/apps/tools/OswAppDistStats.cpp index 5e8f47f17..c7b60409c 100644 --- a/src/apps/tools/OswAppDistStats.cpp +++ b/src/apps/tools/OswAppDistStats.cpp @@ -65,14 +65,14 @@ void OswAppDistStats::showStickChart() { } void OswAppDistStats::setup() { - OswHal *hal = OswHal::getInstance(); + OswHal* hal = OswHal::getInstance(); uint32_t weekDay = 0; uint32_t dayOfMonth = 0; hal->getLocalDate(&dayOfMonth, &weekDay); cursorPos = weekDay; } void OswAppDistStats::loop() { - OswHal *hal = OswHal::getInstance(); + OswHal* hal = OswHal::getInstance(); if (hal->btnHasGoneDown(BUTTON_3)) { this->cursorPos = this->cursorPos + 1 > 6 ? 6 : this->cursorPos + 1; } diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index 4b145b652..7c1548f39 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -64,23 +64,19 @@ void OswAppStepStats::showStickChart() { hal->gfx()->print(String(hal->environment->getStepsOnDay(tmpCursor))); // Big font Fitness value } -void OswAppStepStats::setup() -{ - OswHal *hal = OswHal::getInstance(); +void OswAppStepStats::setup() { + OswHal* hal = OswHal::getInstance(); uint32_t weekDay = 0; uint32_t dayOfMonth = 0; hal->getLocalDate(&dayOfMonth, &weekDay); cursorPos = weekDay; } -void OswAppStepStats::loop() -{ - OswHal *hal = OswHal::getInstance(); - if (hal->btnHasGoneDown(BUTTON_3)) - { +void OswAppStepStats::loop() { + OswHal* hal = OswHal::getInstance(); + if (hal->btnHasGoneDown(BUTTON_3)) { this->cursorPos = this->cursorPos + 1 > 6 ? 6 : this->cursorPos + 1; } - if (hal->btnHasGoneDown(BUTTON_2)) - { + if (hal->btnHasGoneDown(BUTTON_2)) { this->cursorPos = this->cursorPos - 1 < 0 ? 0 : this->cursorPos - 1; } showStickChart(); From 1719b503bd7591e479b98dd3462e16b62cfe4a37 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Sat, 16 Jul 2022 22:47:54 +0900 Subject: [PATCH 105/116] HAL : add getStepsAverage --- include/hal/environment.h | 1 + src/hal/environment.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/hal/environment.h b/include/hal/environment.h index 92e46bfd8..5f352be4d 100644 --- a/include/hal/environment.h +++ b/include/hal/environment.h @@ -39,6 +39,7 @@ class OswHal::Environment { uint32_t getStepsTotal(); uint32_t getStepsTotalWeek(); #ifdef OSW_FEATURE_STATS_STEPS + uint32_t getStepsAverage(); uint32_t getStepsOnDay(uint8_t dayOfWeek, bool lastWeek = false); #endif #endif diff --git a/src/hal/environment.cpp b/src/hal/environment.cpp index 04182b2c7..a38295765 100644 --- a/src/hal/environment.cpp +++ b/src/hal/environment.cpp @@ -213,6 +213,11 @@ uint32_t OswHal::Environment::getStepsTotalWeek() { return this->getStepsTotal(); #endif } +#ifdef OSW_FEATURE_STATS_STEPS +uint32_t OswHal::Environment::getStepsAverage() { + return this->getStepsTotalWeek() / 7; +} +#endif #endif #if OSW_PLATFORM_ENVIRONMENT_PRESSURE == 1 From 0477e6598964c88bb6bb8f2640408ff4d6d5b520 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Sun, 17 Jul 2022 21:21:07 +0900 Subject: [PATCH 106/116] Fitness-stats : update steps average --- src/apps/tools/OswAppDistStats.cpp | 2 +- src/apps/tools/OswAppKcalStats.cpp | 2 +- src/apps/tools/OswAppStepStats.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/apps/tools/OswAppDistStats.cpp b/src/apps/tools/OswAppDistStats.cpp index c7b60409c..ce5948d44 100644 --- a/src/apps/tools/OswAppDistStats.cpp +++ b/src/apps/tools/OswAppDistStats.cpp @@ -58,7 +58,7 @@ void OswAppDistStats::showStickChart() { hal->gfx()->setTextCursor(DISP_W/2, 190); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(tmpCursor,true))) ); // lastweek(before 7 day) hal->gfx()->setTextCursor(DISP_W/2, 215); - hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()) / 7)+String("/")+String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()))); // Avg/Total + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsAverage())) + String("/") + String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsTotalWeek()))); // Avg/Total hal->gfx()->setTextSize(2); hal->gfx()->setTextCursor(DISP_W/2, 205); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateDistance(hal->environment->getStepsOnDay(tmpCursor)) + String(" m"))); // Big font Fitness value diff --git a/src/apps/tools/OswAppKcalStats.cpp b/src/apps/tools/OswAppKcalStats.cpp index 9aa0a75be..00b46478a 100644 --- a/src/apps/tools/OswAppKcalStats.cpp +++ b/src/apps/tools/OswAppKcalStats.cpp @@ -82,7 +82,7 @@ void OswAppKcalStats::showCurvedChart() { hal->gfx()->setTextCursor(DISP_W/2, 190); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDay(wDay, true)))); // lastweek(before 7 day) hal->gfx()->setTextCursor(DISP_W/2, 215); - hal->gfx()->print(String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek()) / 7) + String("/") + String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek()))); // Avg/Total + hal->gfx()->print(String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsAverage())) + String("/") + String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsTotalWeek()))); // Avg/Total hal->gfx()->setTextSize(2); hal->gfx()->setTextCursor(DISP_W/2, 205); hal->gfx()->print(String(OswAppWatchfaceFitness::calculateKcalorie(hal->environment->getStepsOnDay(wDay)) + String(" Kcal"))); // Big font Fitness value diff --git a/src/apps/tools/OswAppStepStats.cpp b/src/apps/tools/OswAppStepStats.cpp index 7c1548f39..0972242b5 100644 --- a/src/apps/tools/OswAppStepStats.cpp +++ b/src/apps/tools/OswAppStepStats.cpp @@ -58,7 +58,7 @@ void OswAppStepStats::showStickChart() { hal->gfx()->setTextCursor(DISP_W/2, 190); hal->gfx()->print(String(hal->environment->getStepsOnDay(tmpCursor, true))); // lastweek(before 7 day) hal->gfx()->setTextCursor(DISP_W/2, 215); - hal->gfx()->print(String(hal->environment->getStepsTotalWeek() / 7) + String("/") + String(hal->environment->getStepsTotalWeek())); // Avg/Total + hal->gfx()->print(String(hal->environment->getStepsAverage()) + String("/") + String(hal->environment->getStepsTotalWeek())); // Avg/Total hal->gfx()->setTextSize(2); hal->gfx()->setTextCursor(DISP_W/2, 205); hal->gfx()->print(String(hal->environment->getStepsOnDay(tmpCursor))); // Big font Fitness value From 95166ab4686efd173e0d7a12b47fc52459a188a2 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Tue, 19 Jul 2022 00:46:53 +0900 Subject: [PATCH 107/116] BLE player : update button - Volume Up && Down with Play-Pause --- src/apps/tools/ble_media_ctrl.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/apps/tools/ble_media_ctrl.cpp b/src/apps/tools/ble_media_ctrl.cpp index a6bbff3ee..1434f82ec 100644 --- a/src/apps/tools/ble_media_ctrl.cpp +++ b/src/apps/tools/ble_media_ctrl.cpp @@ -21,11 +21,13 @@ void OswAppBLEMEdiaCtrl::loop() { Serial.println(ESP.getFreeHeap()); OswHal* hal = OswHal::getInstance(); - if (hal->btnHasGoneDown(BUTTON_3)) { + if (hal->btnHasGoneDown(BUTTON_2) && hal->btnHasGoneDown(BUTTON_3)) { + bleKeyboard->write(KEY_MEDIA_PLAY_PAUSE); + } else if (hal->btnHasGoneDown(BUTTON_3)) { bleKeyboard->write(KEY_MEDIA_VOLUME_UP); } else if (hal->btnHasGoneDown(BUTTON_2)) { bleKeyboard->write(KEY_MEDIA_VOLUME_DOWN); - } + } if (millis() - lastDraw > 250 /* 4fps redraw */) { lastDraw = millis(); From c220e5802fa6e15ec46f7bba6fea6df13bbf680c Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 18 Jul 2022 15:48:25 +0000 Subject: [PATCH 108/116] Applied formatting --- src/apps/tools/ble_media_ctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/tools/ble_media_ctrl.cpp b/src/apps/tools/ble_media_ctrl.cpp index 1434f82ec..c87c75cea 100644 --- a/src/apps/tools/ble_media_ctrl.cpp +++ b/src/apps/tools/ble_media_ctrl.cpp @@ -27,7 +27,7 @@ void OswAppBLEMEdiaCtrl::loop() { bleKeyboard->write(KEY_MEDIA_VOLUME_UP); } else if (hal->btnHasGoneDown(BUTTON_2)) { bleKeyboard->write(KEY_MEDIA_VOLUME_DOWN); - } + } if (millis() - lastDraw > 250 /* 4fps redraw */) { lastDraw = millis(); From df18bfcfd0524a714243b8266ccaa9b5e92bc67c Mon Sep 17 00:00:00 2001 From: Gladox114 <53704522+Gladox114@users.noreply.github.com> Date: Thu, 21 Jul 2022 12:11:06 +0200 Subject: [PATCH 109/116] Fixed Lightsleep not working properly with really long enough button press --- src/apps/main/switcher.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/apps/main/switcher.cpp b/src/apps/main/switcher.cpp index 30644ea83..ea46e5a5c 100644 --- a/src/apps/main/switcher.cpp +++ b/src/apps/main/switcher.cpp @@ -39,13 +39,16 @@ void OswAppSwitcher::loop() { } } + bool sleeping = false; + // do action only once the button goes up if (hal->btnHasGoneUp(_btn)) { if (_doSleep) { _doSleep = false; + _doSwitch = false; // if lightsleep is enabled then doSwitch is still true and will be used the next time. + sleeping = true; // because in lightsleep the next _app will use the button and switch the app which isn't what we want sleep(); - } - if (_doSwitch) { + } else if (_doSwitch) { _doSwitch = false; cycleApp(); // we need to clear the button state, otherwise nested switchers @@ -70,7 +73,8 @@ void OswAppSwitcher::loop() { hal->gfx()->resetText(); OswUI::getInstance()->resetTextColors(); // yes this resets the colors in hal->gfx() - _apps[*_rtcAppIndex]->loop(); + if (!sleeping) + _apps[*_rtcAppIndex]->loop(); // draw Pagination Indicator if(_paginationIndicator) { From 8ce7c05e4804236ad167cc9be961ac77c104d647 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Fri, 22 Jul 2022 03:58:44 +0900 Subject: [PATCH 110/116] OswAppBLEMEdiaCtrl : update pre-processing and rename --- include/apps/tools/{ble_media_ctrl.h => OswAppBLEMEdiaCtrl.h} | 4 +++- src/apps/tools/{ble_media_ctrl.cpp => OswAppBLEMEdiaCtrl.cpp} | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) rename include/apps/tools/{ble_media_ctrl.h => OswAppBLEMEdiaCtrl.h} (87%) rename src/apps/tools/{ble_media_ctrl.cpp => OswAppBLEMEdiaCtrl.cpp} (95%) diff --git a/include/apps/tools/ble_media_ctrl.h b/include/apps/tools/OswAppBLEMEdiaCtrl.h similarity index 87% rename from include/apps/tools/ble_media_ctrl.h rename to include/apps/tools/OswAppBLEMEdiaCtrl.h index dcf388fe3..0b5a89154 100644 --- a/include/apps/tools/ble_media_ctrl.h +++ b/include/apps/tools/OswAppBLEMEdiaCtrl.h @@ -1,3 +1,4 @@ +#ifdef OSW_FEATURE_BLE_MEDIA_CTRL #pragma once #include @@ -12,4 +13,5 @@ class OswAppBLEMEdiaCtrl : public OswApp { ~OswAppBLEMEdiaCtrl() {}; private: -}; \ No newline at end of file +}; +#endif \ No newline at end of file diff --git a/src/apps/tools/ble_media_ctrl.cpp b/src/apps/tools/OswAppBLEMEdiaCtrl.cpp similarity index 95% rename from src/apps/tools/ble_media_ctrl.cpp rename to src/apps/tools/OswAppBLEMEdiaCtrl.cpp index c87c75cea..cc5c609d5 100644 --- a/src/apps/tools/ble_media_ctrl.cpp +++ b/src/apps/tools/OswAppBLEMEdiaCtrl.cpp @@ -1,5 +1,6 @@ -#include "./apps/tools/ble_media_ctrl.h" +#ifdef OSW_FEATURE_BLE_MEDIA_CTRL +#include "./apps/tools/OswAppBLEMEdiaCtrl.h" #include #include @@ -65,3 +66,4 @@ void OswAppBLEMEdiaCtrl::stop() { delete bleKeyboard; OswHal::getInstance()->enableDisplayBuffer(); } +#endif \ No newline at end of file From 11bf537eff5fed9134734fe6d85f725ed37ce2e8 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Fri, 22 Jul 2022 04:04:46 +0900 Subject: [PATCH 111/116] Overlays : remove line-header --- include/overlays/overlays.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/overlays/overlays.h b/include/overlays/overlays.h index d6b6bb58b..c0c574bab 100644 --- a/include/overlays/overlays.h +++ b/include/overlays/overlays.h @@ -1,8 +1,5 @@ -#ifndef OVERLAYS_H -#define OVERLAYS_H +#pragma once #include "osw_hal.h" -void drawOverlays(); - -#endif \ No newline at end of file +void drawOverlays(); \ No newline at end of file From 7974635594f279eb43cbe38ac726c9b6f8a351d3 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 25 Jul 2022 08:40:20 +0000 Subject: [PATCH 112/116] Applied formatting --- src/apps/main/switcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/main/switcher.cpp b/src/apps/main/switcher.cpp index ea46e5a5c..4c0954b50 100644 --- a/src/apps/main/switcher.cpp +++ b/src/apps/main/switcher.cpp @@ -46,7 +46,7 @@ void OswAppSwitcher::loop() { if (_doSleep) { _doSleep = false; _doSwitch = false; // if lightsleep is enabled then doSwitch is still true and will be used the next time. - sleeping = true; // because in lightsleep the next _app will use the button and switch the app which isn't what we want + sleeping = true; // because in lightsleep the next _app will use the button and switch the app which isn't what we want sleep(); } else if (_doSwitch) { _doSwitch = false; From 328f1a53aa6038f65f33bbe1c8109f452e33e693 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Wed, 27 Jul 2022 17:56:52 +0900 Subject: [PATCH 113/116] Update submodule upstream --- lib/lib-open-smartwatch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lib-open-smartwatch b/lib/lib-open-smartwatch index 536c8e49a..c6f0dbda4 160000 --- a/lib/lib-open-smartwatch +++ b/lib/lib-open-smartwatch @@ -1 +1 @@ -Subproject commit 536c8e49a41621a3b7836958d329bb64770be4cf +Subproject commit c6f0dbda470d71b01f0911008ee06ef89afe78c2 From e91aaf41d54cf0c629b12763ba41884301457dae Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Wed, 27 Jul 2022 18:15:28 +0900 Subject: [PATCH 114/116] Apply slice feature --- src/apps/tools/OswAppPrintDebug.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/apps/tools/OswAppPrintDebug.cpp b/src/apps/tools/OswAppPrintDebug.cpp index 3cc8b6c25..e9461d8a8 100644 --- a/src/apps/tools/OswAppPrintDebug.cpp +++ b/src/apps/tools/OswAppPrintDebug.cpp @@ -75,7 +75,8 @@ void OswAppPrintDebug::loop() { wifiDisabled = !OswServiceAllTasks::wifi.isEnabled(); #endif printStatus("Battery (Analog)", (wifiDisabled ? String(hal->getBatteryRaw()) : String("WiFi active!")).c_str()); - printStatus("Hash", (String(GIT_COMMIT_HASH) + " (" + String(GIT_BRANCH_NAME) + ")").c_str()); + char branchName[] = GIT_BRANCH_NAME; + printStatus("Hash", (String(GIT_COMMIT_HASH) + " (" + hal->gfx()->printSlice(branchName, 10, true) + ".." + ")").c_str()); printStatus("Platform", String(PIO_ENV_NAME).c_str()); printStatus("Compiled", (String(__DATE__) + " " + String(__TIME__)).c_str()); From 3a62100839e81347bd9cbcdcdfcd45f8372bcc58 Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Wed, 27 Jul 2022 21:52:01 +0900 Subject: [PATCH 115/116] i18n : clean translate-part --- include/locales/cs-CZ.h | 16 +++++----------- include/locales/de-DE.h | 16 +++++----------- include/locales/en-US.h | 16 +++++----------- include/locales/fr-FR.h | 16 +++++----------- include/locales/hu-HU.h | 16 +++++----------- include/locales/it-IT.h | 16 +++++----------- include/locales/ko-KR.h | 16 +++++----------- 7 files changed, 35 insertions(+), 77 deletions(-) diff --git a/include/locales/cs-CZ.h b/include/locales/cs-CZ.h index 299b41201..d7ec7b8bc 100644 --- a/include/locales/cs-CZ.h +++ b/include/locales/cs-CZ.h @@ -29,26 +29,20 @@ #define LANG_WATCHFACE_FITNESS_DISTANCE "Dist" #define LANG_WATCHFACE_FITNESS_STEP "Step" -// App: Step Statistics -#define LANG_STEPSTATS_TITLE "Steps stats" -#define LANG_STEPSTATS_TODAY "Today" -#define LANG_STEPSTATS_TOTAL "Total" -#define LANG_STEPSTATS_STEP "Step" - // App: Fitness Statistics #define LANG_FITNESS_TITLE "Fitness stats" #define LANG_FITNESS_STEP "Step" #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" -// App: Distance Statistics -#define LANG_DISTSTATS_TITLE "Dist stats" +// App: Step Statistics +#define LANG_STEPSTATS_TITLE "Steps stats" // App: Kcal Statistics #define LANG_KCALSTATS_TITLE "Kcal stats" -#define LANG_KCALSTATS_AVG "Avg" -#define LANG_KCALSTATS_TODAY "Today" -#define LANG_KCALSTATS_STEP "Step" + +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" // Weekdays #define LANG_MONDAY "Pondeli" diff --git a/include/locales/de-DE.h b/include/locales/de-DE.h index 8d1e00662..d74467167 100644 --- a/include/locales/de-DE.h +++ b/include/locales/de-DE.h @@ -29,26 +29,20 @@ #define LANG_WATCHFACE_FITNESS_DISTANCE "Distanz" #define LANG_WATCHFACE_FITNESS_STEP "Schritte" -// App: Step Statistics -#define LANG_STEPSTATS_TITLE "Schritt-Statistik" -#define LANG_STEPSTATS_TODAY "Heute" -#define LANG_STEPSTATS_TOTAL "Insgesamt" -#define LANG_STEPSTATS_STEP "Schritte" - // App: Fitness Statistics #define LANG_FITNESS_TITLE "Fitness-Statistik" #define LANG_FITNESS_STEP "Schritte" #define LANG_FITNESS_DISTANCE "Distanz" #define LANG_FITNESS_TOTAL "Insgesamt" -// App: Distance Statistics -#define LANG_DISTSTATS_TITLE "Dist stats" +// App: Step Statistics +#define LANG_STEPSTATS_TITLE "Schritt-Statistik" // App: Kcal Statistics #define LANG_KCALSTATS_TITLE "Kcal-Statistik" -#define LANG_KCALSTATS_AVG "AVG" -#define LANG_KCALSTATS_TODAY "Heute" -#define LANG_KCALSTATS_STEP "Schritte" + +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Distanz-Statistik" // Weekdays #define LANG_MONDAY "Montag" diff --git a/include/locales/en-US.h b/include/locales/en-US.h index 2e9462f55..b75de7123 100644 --- a/include/locales/en-US.h +++ b/include/locales/en-US.h @@ -29,26 +29,20 @@ #define LANG_WATCHFACE_FITNESS_DISTANCE "Dist" #define LANG_WATCHFACE_FITNESS_STEP "Step" -// App: Step Statistics -#define LANG_STEPSTATS_TITLE "Steps stats" -#define LANG_STEPSTATS_TODAY "Today" -#define LANG_STEPSTATS_TOTAL "Total" -#define LANG_STEPSTATS_STEP "Step" - // App: Fitness Statistics #define LANG_FITNESS_TITLE "Fitness stats" #define LANG_FITNESS_STEP "Step" #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" -// App: Distance Statistics -#define LANG_DISTSTATS_TITLE "Dist stats" +// App: Step Statistics +#define LANG_STEPSTATS_TITLE "Steps stats" // App: Kcal Statistics #define LANG_KCALSTATS_TITLE "Kcal stats" -#define LANG_KCALSTATS_AVG "Avg" -#define LANG_KCALSTATS_TODAY "Today" -#define LANG_KCALSTATS_STEP "Step" + +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" // Weekdays #define LANG_MONDAY "Monday" diff --git a/include/locales/fr-FR.h b/include/locales/fr-FR.h index c63524c8f..1355946cd 100644 --- a/include/locales/fr-FR.h +++ b/include/locales/fr-FR.h @@ -29,26 +29,20 @@ #define LANG_WATCHFACE_FITNESS_DISTANCE "Dist" #define LANG_WATCHFACE_FITNESS_STEP "Step" -// App: Step Statistics -#define LANG_STEPSTATS_TITLE "Steps stats" -#define LANG_STEPSTATS_TODAY "Today" -#define LANG_STEPSTATS_TOTAL "Total" -#define LANG_STEPSTATS_STEP "Step" - // App: Fitness Statistics #define LANG_FITNESS_TITLE "Fitness stats" #define LANG_FITNESS_STEP "Step" #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" -// App: Distance Statistics -#define LANG_DISTSTATS_TITLE "Dist stats" +// App: Step Statistics +#define LANG_STEPSTATS_TITLE "Steps stats" // App: Kcal Statistics #define LANG_KCALSTATS_TITLE "Kcal stats" -#define LANG_KCALSTATS_AVG "Avg" -#define LANG_KCALSTATS_TODAY "Today" -#define LANG_KCALSTATS_STEP "Step" + +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" // Weekdays #define LANG_MONDAY "Lundi" diff --git a/include/locales/hu-HU.h b/include/locales/hu-HU.h index 9a3dbb81e..874b2685d 100644 --- a/include/locales/hu-HU.h +++ b/include/locales/hu-HU.h @@ -29,26 +29,20 @@ #define LANG_WATCHFACE_FITNESS_DISTANCE "Dist" #define LANG_WATCHFACE_FITNESS_STEP "Step" -// App: Step Statistics -#define LANG_STEPSTATS_TITLE "Steps stats" -#define LANG_STEPSTATS_TODAY "Today" -#define LANG_STEPSTATS_TOTAL "Total" -#define LANG_STEPSTATS_STEP "Step" - // App: Fitness Statistics #define LANG_FITNESS_TITLE "Fitness stats" #define LANG_FITNESS_STEP "Step" #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" -// App: Distance Statistics -#define LANG_DISTSTATS_TITLE "Dist stats" +// App: Step Statistics +#define LANG_STEPSTATS_TITLE "Steps stats" // App: Kcal Statistics #define LANG_KCALSTATS_TITLE "Kcal stats" -#define LANG_KCALSTATS_AVG "Avg" -#define LANG_KCALSTATS_TODAY "Today" -#define LANG_KCALSTATS_STEP "Step" + +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" // Weekdays #define LANG_MONDAY "Hétfő" diff --git a/include/locales/it-IT.h b/include/locales/it-IT.h index 6c1ee0ebe..98cb94f7a 100644 --- a/include/locales/it-IT.h +++ b/include/locales/it-IT.h @@ -29,26 +29,20 @@ #define LANG_WATCHFACE_FITNESS_DISTANCE "Dist" #define LANG_WATCHFACE_FITNESS_STEP "Step" -// App: Step Statistics -#define LANG_STEPSTATS_TITLE "Steps stats" -#define LANG_STEPSTATS_TODAY "Today" -#define LANG_STEPSTATS_TOTAL "Total" -#define LANG_STEPSTATS_STEP "Step" - // App: Fitness Statistics #define LANG_FITNESS_TITLE "Fitness stats" #define LANG_FITNESS_STEP "Step" #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" -// App: Distance Statistics -#define LANG_DISTSTATS_TITLE "Dist stats" +// App: Step Statistics +#define LANG_STEPSTATS_TITLE "Steps stats" // App: Kcal Statistics #define LANG_KCALSTATS_TITLE "Kcal stats" -#define LANG_KCALSTATS_AVG "Avg" -#define LANG_KCALSTATS_TODAY "Today" -#define LANG_KCALSTATS_STEP "Step" + +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" // Weekdays #define LANG_MONDAY "Lunedì" diff --git a/include/locales/ko-KR.h b/include/locales/ko-KR.h index 57a056fec..6c2ddea8e 100644 --- a/include/locales/ko-KR.h +++ b/include/locales/ko-KR.h @@ -42,26 +42,20 @@ #define LANG_WATCHFACE_FITNESS_DISTANCE "Dist" #define LANG_WATCHFACE_FITNESS_STEP "Step" -// App: Step Statistics -#define LANG_STEPSTATS_TITLE "Steps stats" -#define LANG_STEPSTATS_TODAY "Today" -#define LANG_STEPSTATS_TOTAL "Total" -#define LANG_STEPSTATS_STEP "Step" - // App: Fitness Statistics #define LANG_FITNESS_TITLE "Fitness stats" #define LANG_FITNESS_STEP "Step" #define LANG_FITNESS_DISTANCE "Distance" #define LANG_FITNESS_TOTAL "Total" -// App: Distance Statistics -#define LANG_DISTSTATS_TITLE "Dist stats" +// App: Step Statistics +#define LANG_STEPSTATS_TITLE "Steps stats" // App: Kcal Statistics #define LANG_KCALSTATS_TITLE "Kcal stats" -#define LANG_KCALSTATS_AVG "Avg" -#define LANG_KCALSTATS_TODAY "Today" -#define LANG_KCALSTATS_STEP "Step" + +// App: Distance Statistics +#define LANG_DISTSTATS_TITLE "Dist stats" // Weekdays #define LANG_MONDAY "월요일" From 1440f74d2352a3ade592b40a27e6cc7f0c9cc92e Mon Sep 17 00:00:00 2001 From: RuffaloLavoisier Date: Thu, 28 Jul 2022 11:44:35 +0900 Subject: [PATCH 116/116] libraries : replace lib-header --- include/apps/main/stopwatch.h | 6 +----- include/apps/main/switcher.h | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/include/apps/main/stopwatch.h b/include/apps/main/stopwatch.h index 8a6d51439..dca2956df 100644 --- a/include/apps/main/stopwatch.h +++ b/include/apps/main/stopwatch.h @@ -1,6 +1,4 @@ -#ifndef OSW_APP_STOPWATCH_H -#define OSW_APP_STOPWATCH_H - +#pragma once #include #include @@ -37,5 +35,3 @@ class OswAppStopWatch : public OswApp { char lapPages = 0; char lapPage = 0; }; - -#endif diff --git a/include/apps/main/switcher.h b/include/apps/main/switcher.h index f7ef299b8..b5eefe844 100644 --- a/include/apps/main/switcher.h +++ b/include/apps/main/switcher.h @@ -1,6 +1,4 @@ -#ifndef OSW_APP_APPSWITCHER_H -#define OSW_APP_APPSWITCHER_H - +#pragma once #include #include #include @@ -46,5 +44,3 @@ class OswAppSwitcher : public OswApp { short _timeForLongPress = APPSWITCHER_LONG_PRESS; short _timeForSleepPress = APPSWITCHER_SLEEP_TIMEOUT; }; - -#endif