From 5688f4bbe5f52478ff2656b8b5bb132e78993f73 Mon Sep 17 00:00:00 2001 From: Xu Chun Guang Date: Sat, 6 Mar 2021 17:29:50 +0800 Subject: [PATCH 01/57] fix: Sometimes smartconfig terminates since send UDP fail --- components/esp8266/source/smartconfig_ack.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/esp8266/source/smartconfig_ack.c b/components/esp8266/source/smartconfig_ack.c index 7c4347470..a71b62f3a 100644 --- a/components/esp8266/source/smartconfig_ack.c +++ b/components/esp8266/source/smartconfig_ack.c @@ -180,7 +180,11 @@ static void sc_ack_send_task(void* pvParameters) } ESP_LOGE(TAG, "send failed, errno %d", err); - goto _end; + if ((send_sock >= LWIP_SOCKET_OFFSET) && (send_sock <= (FD_SETSIZE - 1))) { + close(send_sock); + } + send_sock = -1; + break; } } } else { From fb5894a9dd9ddb4b821a58c3ce98d7bb9761e36d Mon Sep 17 00:00:00 2001 From: Zhang Jun Hao Date: Fri, 19 Mar 2021 11:04:39 +0800 Subject: [PATCH 02/57] fix(lib): check and reset mac reg every 2s when rx hang occurs --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libpp.a | Bin 245990 -> 247158 bytes components/esp8266/lib/libpp_dbg.a | Bin 263422 -> 264598 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index 49d4d2e10..b2c4332be 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,7 +1,7 @@ gwen: core: cebfb0e net80211: 8114f9c - pp: 52bb147 + pp: 5fda74f espnow: 7a93d71 smartconfig: 3.0.0/5f550c40 diff --git a/components/esp8266/lib/libpp.a b/components/esp8266/lib/libpp.a index 761b8be80a2336113730e58f643b2eb9fb9f3e83..aa59f60fd5f95b5d2039d38664bd642a2c66c5c7 100755 GIT binary patch delta 22466 zcmcJX4RjR6n*O_bk`S257sLb%keNwHCJ-QBVt@c4$*I|1|plr;h(ee#8F9J^imc(9-63EzX|P zEsdRKCE5w2u~SlHLI1p*LZh!QQ!jhErOHz*TK`#Z-&(taA${;@YQx|Kx*HBFl~OCLU5n|8Opd%c!1T94YIMdfSLZc6b4 zOtIC3huFgH{@!l!I$^kuGTkG^W+q(v?j{ZCoAlkiwD||z^Wvu^$9mKCqy?JS+kIN4 zKKvQY)ls}i-&00Y|8D-LtzsRc{-%iy#HdHK);^1qP{(zy12a=ZBgNeY(qkfaM_6^I zcpf&z8tS2~OBat?wNx%%sAUY+hcD5F|7xNHFamu^^eiyN3d`TxqT0oNEu)Vfb&r;b z-aO2#2?x3Zms<7Y?YyIS+|8_eA4#uEcN`)jnITPusI zsWFR7f)%B~oYLTkSM}l7Xf;=vH(zU7nSbP5s_z~jDp2eVR(OLsc|p$@(-k46SlzO= zuE~r4!u{)0fCeX7eL9P{yf)0uj@W025XCVVsEt! z4EjLrg8}A02AV_rvj>GSb#dP8&ZWPAcn{T2IbMk}L`N2y! z>x+AbWNK-_+}>ujHwf?DnVP4EDF(4KsK_dbnudB!e~vd;7>7+>x>nMtaeq=wQ9#Gz zGgG22Mt_da>^g0XzBpdXd;eEgl1tCYScqxeI@viGl$0ktai++!cHhVC@FTNxC^Lxx@F?eEKHpXHzx?MgNwoiyn#g|8n#9 z5&zQLzm$_6e0$xe%S#%and$oCU7EL3#Ey@#PYK?c7X`E3c{Q5&lGS>%Qwl}K~hxGmXBbI(HKBXAiF5aklc9{pt7nFHDZ zd)*%y6S`d}{%GNZH_m(0G2vgCoPE)|X-8Hqeo`yZMarTpefsW3ty0%|l~%rWzT&{b zQC|0T!LNH9OZq&+^RhK!Q=*Aj2n(#(}ZD!Uf1h>56hA1sLx z?QV!%(5NjaU-Z0p{z-S*(E9uR@%QC*E7^5nR9SKH+{}WG_1<95-d;Vjq9Xmu$_SV4 zEyrY9)Vkj5dT2tWhPmV|U*y}kVBKwH9X+ee%U7E{OL3IlrNQD6L!IfFg^8XO=BN^H zgqGsy|269d|ZEd-MnWOV-WnxqAIb&AU^K zSn(q??2pe;*lBc>EAobfJ49$b=1w$g6UsIY=vOB)TcQdR2lT^k6ehaUg5H^(k7sxO zHp4qJXrg!%slW<4w)!3_fa$(>=nh+X|*8C}8l&g+DP2jQ+`?WJj;BLioib5Cd#!}f`1U5!? z!Lp)WU=*?RY;dB|i^2AxxeXkn^aWu)tHAcCzW^?@C*xO0Ft9PQ-HG48%%aYNZSQdo zn1MRk4eLd$0Nb6r9NbRnRbYFhuLavXd~0r4fw^FxD)1PXfeny*!Lorp4&&Z`Tr9W! zCR{DoUArVPatXxsE#KW7C&ZAJ^S8|I?q3Eakvo9Ugh=LWcttU*TIl?VixG4n2lYkm}TcG=JcAUxGVTh#hl}7 z6uZHkPOLu>?Q6{{kq-VyF&jInm<^=jsIowBXuTA(u|A5~7-t84*jS}vH+Z&U)_<2` z*1rtww+lQOma$PW_wsecoD@9u(4U3B4AUc#N1gti74sDI6#S@j{=5*zFaN=Q?Jbqy z#M%?a?YUxZ6tfdnz0i4)^`WC;6E+B!`jr#KOTkW+ zk&U!iLKjUNqYGkL<*&sW_)l`5yyUuY+_furTu9SPt0@Gk; zDCQOY<}jWY#&;^_UKX+eo;VQf9iv8eD*dm@pLYWf37k>c7!#|)GS-H15h@T5u}Yk} zlunK8RC+PeVm&qptc!IPD|RZK$DBHED;UYG;z~^`g`?oJ2f|L3L5=KGI&V2xfVUWo zWZqVk!OuRHpDCT%XU5u9$^JH_ltUrgV_d;f>HwWoKGewefn)7#g=eLo6myJux}?sV z6h<=dOUAQKHF-LObiXAsVb7{6I;q(cuL@Hm+nr-&tket3D=C=`Ph?qj5Yv@Tjcgy> zo?-sgyjt3O*;i#$qX607%OOht3v7vE-Zf1PYixwlsgdo*Mk}2Me1hVMuvghSr`=?g zsD-`W&VYWCVxG8f4$~VH^V)AH=H5SJ`@lXMrteU^2X2ngNK0kjC1I(4#8QaQzP4>a!%>!G+uP7lXN@S2*uo+7{#4nYn)P!Z+rkIzZx-fk%_e{;+dz4O%Y){@g z`lyk6TKP~T+anrKI&YZY@v8(cTOTOqUGn^}#y(LxHL~4UJ$=+l`CR!>Bik$G2c`2; z_mg7YRWD*$EbmdU+OH~uBH5n#bhMY2OEIspabbMX@7!|m(MLP^n@~rhkF{!{%O)5u zp-UooGwN?cnm*C6KPjgEi((h7;5h_7@!$-_^ckf%5&D&iyMiZ$*l*ogyrnYS$k?kG zb!mqcr-QAN6hyLhJ^_0$F@2nz;DNBi6lcTdTE#iwYQ+WM)rt$jPw1FWEL?=dew9%S zKCbv1*z=0VVQ+dP(!UIr6O>#9J4Z41_>nMPi@NB;yO#Be=~D`}<|f+LIREHGk!;VG zol4&iTZU*)=DkX%Mz;MwRC*h1Iig?%2p=J`erjZ=(ocdt%;0gXK(q^d3#Lx(Tf^U+ z>_4NF@vvm)BiJCss{_Pplfu}#$3YF$)0NI=G3yQ;I&aRc`xme^9?FN$ZX*;^zcIvq z>k52_%2)u)$SyX)E>+BvwhZH^!nj%SHrQ9f_>kf=u+}9JbzT5lH}2qVI&S3bS;9+K zG9nx1gJM6$#ju=y)cHU-M=>7)t-E#T3&6{j&I^Hc=MH@X_!XtU0Lx3KScwh7J4&zO zEMdZ_G7hT@J}CZEF&_>cYU)+NwpYxDK$l`ZD8?%0L*PWzE8b*NxHc=D8riAzeqcZM zj0LKZX%`rRG<9lZy8zdT?O&^y50+C|b~82zH!7VP*{Sq-O6LRTe8q-C8?4pBQEXsQ z^hRY+BRiEo6KT;x4^6vI`B1yh7~7KUe@H2FppczS^uuEoqF8UChNi5pQzP5=d3E&J z8S-J*xO>#d_G((MbWYp(^jE#w5Yl^EA`^CZ>*=Jr`@AYl?Rg_^Q*sR7;jo!SP+o4y z-&C6{e8yw%E)-dYyLFQ2Y1Fq46upeCt$jtdaSGesM%VX7`1`;e;RN31h};mLA?Jno z0y#g#(Vf5rAxbu$b&-MaUv6gLy21Q5aaT~K7j|E zB3f_hzP~wAG#dLp8Y`NN)Q`uCR%14{CyedbUNGW587u0IN!T7VHhwZzFBre#&=@ht z7<*`}SYoWjw$V6^?Pg=hr(?yB#d_O7woh-@Bd#>6J{tq=na{?Gna0o9E;2?O z9xFB(65A8TH`rb84OsL>ug}x;u8Bs)=NWqE zTaCKUGsG!l?dO?#*V~M}(BhMfGtkZ%$zNom@*!Vj>aIJC+AlK1Nn;rjg?Ad8k?IHWhRYx<>6F(B2=NnB(lpFhyzrpw!+m%LYTPAjV1hx&v?6yq3 zXo0c1Ekln;F@i927aAwqSU&C;n*6I#cq~JlF(w_$#30^xEHkpAD;{!=T$1}uIBlCEsIAV-Fo~h?NY}7$oZLEc~)!2jWCgU`=ZAS8!nc|Q!3zSaW51$* z>R0sN{#CMZot2*bd-_GB%aM~QDvWQeZQR$HdWBcUZ+0XZW4?}uJ}IQQC+bPY6Ht~K z8^6vJyNpk;-E5d&XGUhHV;LL0zDbKbxPmn9n>0+7dEYR9Ew)X@o^N`Ff6Q%(J-M$> zxDZj0*RRm%>Q8#N170mP5QroV@cl ze7nkh*(~vD{D?Kt9ag>e!A3Lp1v6Og{{542=)*C_v@eYAkm>Kem zXh*udE<$$&`VA0A^xw1Z*7=6h_-(W+P%=nt?ku_l&R-!+A-)Qnzfz>d`1#@^kuO#e zF!eMs-9l|P40UQ`r_ym6*F-Hg2zMgVhZ@DD6w^ouZDrO31Wt+!;*sgZ5}GWyKI27zT*CpEHD>E%eH zOS~b{v;oSABH5|>TCDU5uocL&$F)r9)X4U@jtTQ0Pk;QFiNSi&g-%c-JC$Cg$)f3^ zL+*8|Tov-kP9Agw-a?5v7HU(K54EX*dDF!+QGV;uBvI4c(1M7G;7zdBAl(N*@Ua|p zYGkL@^3gq>fpv3c*xa)X4U%kHpE6W6#e3^O0x!cTzevvh80_AGI2+PX{PV zjcl)yMf91X#lqmItBMxMqjN;E|7s*Tf9zo_SJ~9a_AufH4pzVDzm)!J@{d- zHuhhIiL%@AfAGa#Ihy;?-3aLaKtbLCw$OXZU^=j6LIN94cL%#kUZ zU`pjMnld>9CUQwTO}kslO(HF-=?XkjN6O$P;nkx%th!21lD}>e@nW-dzJdZ9WIoL% zc@51exe!Lro+zJxMPy*GKBQVL&(my>X|EzvtC8ieB6F*}mC5uP`52P=xfr>Biz7*X z_9`l`mfs-{E}a4}2jxJRs6+9Z_HcVSf0ynRd*y?WB5U!Bpu6R}yYw_YzD^zqpxTqt zu^DCd%U(3&SX@waJ)0r{Ek26 zhGhBZ>nJ}z)u{eDIpI$ogc|%RNq!3tOr7(rOGyK^ppd&>mT$pc*2`PBAgkW;PAH7} zk9%1!-wfr->T!Bf$Lo;IJH8PT7hEvg_s2 zt!VFrY(Y}2l!sxWTzIZq7G=!;#w#9^z1~2^V{+UZ;y>K%1|EGw+?pPKw;P$CmzPr@ z*S;Zq9eF0fkQG?X`Lr9g=`uG(bd`TSF7A!0taA6L>kx2!DRzp$?h~Rcp&}^G4xw*^ zc6LZ#SkpB9b6g>fdLd#k=IoGNi1F>T>aFk(B7Y<^@fL4x$Tx^`+Y$MAm{Z+3l&R%@ zVS2tW@tew^TdQ?c>FsZRyXMo&|2{NlnET3AlXo04p;u;WA738{D0Fx}GKF;mj#OT@ z<~d-x)8fJ2nOf+#V4L%*>MZ6O!NdY&~iJ0;;qa;O87!@5=WHfjR*;ArC! z_S{{z%5*v4oi`c3fr=K^?=6q5GCh(t7sk5N+^|`(+1}7kEj8-fAT-0<0Y0I*x*laV2AFsI&`)5 zDFs(1tSkQX>a2M&79|_l3xVmh!09A?nVv9j>h-rzs+~7!R?U=2w_Jbg^>d9$x4Grx zUG#h5DAMq3swa0TLqUWz#6;B3I?2v5S%K_9YAxd2VP&%!vQz0Uuo#66LJ=aXphk9% zk{d48)4E&+Mz|W0+1w+t^D^0Xu|A_qIT#@uF%dh$Y_hXlPEFDKcEKf_AqP=-Ewr+Q zXVn0`d*GcEeYvo!Sb=O_=f}g6QN`SD`nWD*LdBBNIJ2veBs<5*wr+Y~F;>QR*OOs< z-Su}xno(gUV{lxldYY(|IjP91lx0Zu7#FH%GEAa6d6S(=XD$jhu*7KDl&TM$#hxJC zf|!V*2m}#S4@VHL~r)^PTO(XF1kGjcogLwR~iSTTk|@>fDxu4Z!C(=DxHUmU$PnG*KR!_MkOd%d<_Z(P0*=|hd|RC)nes5<|qe5jF~N2M%WFw~8)PEHCSkAQ8XCWFPn_;G80>eVG3fL)qWJFq?;q?3^fDefmJV zi~ZOLve^eRy6Dc*(?(u}G=lXJ4%zGj*{Sq7su+J*QHVUD2E=+SgFiLvv8-G!&C>gh zoQgDp^mKvcSRCXD%$xfwT zP&%KS*fF7+>3}q=qeixyub@v2HV8?|hZ@;gBO81EF<#cg4XUU@w)JpRZqJg=z4UpQ z9u2*$S<=)Cvwt+tb=~E~+4}wVc=H_3cj@u4WQ_OLY`B)o_}+SQ4>gQj>h=@kd#VIA zGLCO~Z%l)Uat=zsEa`16v?IOs5q2wiERz^IDU;DkQ6Fobt0~>kM_*$*b3G?sga}K9 zb7^0Fgxwcw0wJ62TN6n2(K`K1kS27I%4RcU`&rx##%Kj|tzpg?pbtd7iFv5E7C8vK zbR;H+>LojC<*B?s>YcB$Sugod^%m#r$u(*Zk^B3DG%w?c90CNg{U99ywl9UurVll; zQ(Yo0A6{NnK!-Qy>kE6RwZyf>kMhy5WP6Rdz~U-dU4T8kO4b$VX;-MHXRdsf;3Oj3 zPtP|fy_6PFs1|NlIyJK00y~MS&!B}a%9STiR^158AriBt`x0cUmYY=eVps<3O2s95 zPf;k(_t(4n-Ii$WyihxA?FH5mgEbJTAzlKLm=fX#6*K>7#T<=*V%D)+G57fk#oV7r zu65KC59{ZK3GP@Y#oUWh#cuFu#p&P*#o6F0#XfMgVxTrlaSr%4#XL-Y#f4xa#D43< z)~qtvyAKqzfv*%7gHI~vk|JS*g4i;jduO^Wyt!405T|&?Y*Ch zwC!WP9fS`x>+PT#p<4P>VuP?mH9(DQkI*Wm^H9%3p176X82>dYgCf}($_V|4YOdv^ zty4a8kR&^mPNOOc{ni+rqsHGI+x67Z=QeB*j;ea7k)5}3{1JFs6W3U%{i>X(k?or& z>u2d`fR9qc)#M`Av#cXjc9hbok)6;xgBKy%$DU<)2&h$bqm#O`i=dMS8x@3Ct}e7L zRHq8{5wqB7ggnH=ZitGVN@p`d@g(I#jcogHVcR|nln*ts?c)ZEI@#DC=g>O2xxd~b z?g-2rptlo)RPAfwk=Q+S$3nJC7Fi{+L9iARe5jF~b+UP&o;*@ju@@4nD2655Rg{A5 z4t@xx4>hvwQ)c`wBv-UutF?GgD>brRtM$tn=8P$Szu{)u5uycc9e)X28e45eQITOH=l*8%jWMz;Oyl+Irm zPYv_GN9oka@W&GX0#_miq;4nnpl02Fsv+kx zvwec9I%;Gb>@#82?N`|>Nw)W7epnS>C?9HM+o#_0krjh+r>9z8M2Yt|2;Zw>)X2_x zvLaF>%kNf+^uV6MdSc8-tTcunF&IKIpS*2$k-LU`I)`z380T0l>o$lHaz?q{FbLzp zkQjrqirrzHO->E@6q4N`E+wb&#~a44USHt4(RzGj`-uMd?uz_cIj<7;s6WazG%Mxy zN^lMK9H^oGPNI59 z`lbpQ$2xO<_lI8 zYpL#%+o`tUj&rZo;nP%4$haz~P388u52=EhBPUU<7_DjNEZ=2RSIUi4%f{jwV5vu` zW=oUmUYuY;YTv7%?v-P&qA#wJq22IPJtNmrZGgJLs$m~h3^3IKoN{tP1AMif8r9Yb z*EU_2UafoEPeqp7+QHe#(#I#shO03ei*N!8mDo;sW|C~9ya_U2DAmfiYasiQWzIE_ z_u~GQZ^CNjB+A)ctatOPuF>Pcvi=&pTYv6P@9*Km?+)AlQ+dFl|4&9Q(XJiPmKDB( zA7yrx0j=?kea9c6w+l(uwzdmj-gk_`E2OYmw8k!S4&40$I;$*JMH;SClNaeJh|I&n z)jIvD{E~}t_Qy)JgI#y*pXxg`DdflV=ksvw0kG=7V z7TxC)MVay3Hz|<^FTsy9<&ASR-P`w0I2-GYO(^T0^^$i-d{%;Ii#c*fmT)Ea zjvF2GZ^wl7L!ITXn!cfhUEXWo-`jMox1;|D$gqA#Q}}_eYhhZ`u}tG+;f|UY&C1w> zoSqBHmKVNsLqg4SX3zATVGZbwyVT!!gK)KT4R5<50lf`MbC@XeSO?%3wnO;S;DS-s(bFE9f=&_>yDhl zs!)MGtPQGsW+h|1a3W|_t3@1@{up}hs7@e-%))^d>6l1 zcs__<@0zBzI$_Tp9dqN(d*aWRJiREe;k2F?<->=NHjY*90n@Xe`_Nzad|>A8Q)8g4 z=Y4tMpL#~uw|@VUGTJrBg|hFk>}ZgyQ=s@KJ*r)d4BgmZFYpH+^0I&FmtyH^^_mNp z)_(Hpf9kRR<^wee9~?0+|I8d6;~M6DYQxT&j(Sa}<2CVTYvRO7R{5Tubf63V`;g=7 zj^K0Chvv7ZLjU`LIBs=zzv^t6jd*u6c- za-Hex79W{@qz|mm$=zk{KT==PxC%e&vVOdlyTkNuSmMrxHX`fZ(2v(VFPSx4&G^gR z@wxowRHl1(o-8hXWu)V>{OK#c_q=Ml(kwZrfZ3t%PWt>0?e9&w8%=NH8G2w2(F48o zT>d1x87y*NwOqWy&UqTq(?PMJZ(&#i?CB7@}|Ji zNQcx#LttLCBU!KH%O>oJb{Y{QV7(bT13MX!dL_h6L@)Rb3JB4N$%!*<-LQcmm9Oe{vNvai?POj8G*{bayODj%4A(fy{o6 zPEP+Ca3W497?RN6l7iWrBTDCG`>5i0*i(x61@TwKiLln2ER^jG&Os+wXIJoF6uZIJ z^A+@TFh2~!$8WtjdO|s6Bcn-i4mhZ|0DM4kA^5oBBJhuji@}NL6dNuD`xKXfa}<|@ zOBGju%dJ0sK!Nc{Oi~$cu=NWc=(t_eW-EOn_;$tfVR^jRST%GWFY;6{zqOKC=id~w zqfa1GKLcBfD3)R4N94L<21T-y83>;t+688UMFUm*7Y2ybsga#Z_o$KJD9nK_mScl3 zMCsJXPNmO9TJ{{~aQB#|JUBJ$pxPx@DxKO&IeVBRxlgp(qxq1?c4fCHoujf)@e+Mi zu_Gh!{xC;T&yj~vfGg!zqS9?VnG4!CqL`5F!!HtLCDtx)X28aRIu$6 zt450&+4iaZ!^a=`J9tz?(HrJ8^A9KMTP7Q$)-TM5S6b>kgX$yWW}SXHCe8v=`7nGb<7Z5WceD$Kyk5LvIZ_Ga`PI;Gx!}^ z^m}8Pim4%NZ<(Bo2BhMq7X}q$HCQZga0h2C^X?n;xG#Rq-2^7eb zCz*$dgPq%eWRKwY9Ra1<58k z2}$hAeN-bdWiwR0qEQ}V?hcPsz>9OqWNgHpq6b!fcX#X71PPs?+! zqF|{^4Ir8Qv@8oCSu1BVS^BhG%_I&alM|noCz?+)ou89cNJbvPz5fika0}*E&U3h9l+OY6vI73B zIYW1El;>z&mq_5vDz?v__@j1*QB#X=kV% z+$KA3M^7u{knQMcMX0KKwmahS>*{5c8V2%3qkNyzUU`&K+cp^;#Gq8;95Geq2Qet6 XJBZf+F>?N(HJ;DV)X9B8NAmvz0y(%j delta 22034 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 delta 23783 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 From 4581aa52d18a0c07eb58cd8d544135add3f46edf Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Mon, 19 Apr 2021 18:10:57 +0800 Subject: [PATCH 03/57] chore(ci): Modify CI image URL --- .gitlab-ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 99d6d5c9d..83b515304 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,6 +7,9 @@ variables: IDF_PATH: "$CI_PROJECT_DIR" + # Versioned esp-idf-doc env image to use for all document building jobs + ESP_IDF_DOC_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env:v8" + # before each job, we need to check if this job is filtered by bot stage/job filter .apply_bot_filter: &apply_bot_filter python $APPLY_BOT_FILTER_SCRIPT || exit 0 @@ -79,7 +82,7 @@ push_master_to_github: build_docs: stage: build - image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + image: $ESP_IDF_DOC_ENV_IMAGE tags: - build_docs artifacts: From 3e92464e82d9e648e937aa3aafeae2519657cbb5 Mon Sep 17 00:00:00 2001 From: yuanjm Date: Thu, 22 Apr 2021 15:12:37 +0800 Subject: [PATCH 04/57] esp_tls_wolfssl: Add domain name check Commit ID: 39b446f9 --- components/esp-tls/esp_tls_wolfssl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp-tls/esp_tls_wolfssl.c b/components/esp-tls/esp_tls_wolfssl.c index 7ec5ee383..f1f87524f 100644 --- a/components/esp-tls/esp_tls_wolfssl.c +++ b/components/esp-tls/esp_tls_wolfssl.c @@ -242,8 +242,8 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls return ESP_ERR_NO_MEM; } /* Hostname set here should match CN in server certificate */ - if ((ret = wolfSSL_set_tlsext_host_name( (WOLFSSL *)tls->priv_ssl, use_host))!= WOLFSSL_SUCCESS) { - ESP_LOGE(TAG, "wolfSSL_set_tlsext_host_name returned -0x%x", -ret); + if ((ret = wolfSSL_check_domain_name( (WOLFSSL *)tls->priv_ssl, use_host))!= WOLFSSL_SUCCESS) { + ESP_LOGE(TAG, "wolfSSL_check_domain_name returned -0x%x", -ret); ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_WOLFSSL, -ret); free(use_host); return ESP_ERR_WOLFSSL_SSL_SET_HOSTNAME_FAILED; From 7b92080927fd30a88525375d7c5bc07d92f3662b Mon Sep 17 00:00:00 2001 From: yuanjm Date: Thu, 22 Apr 2021 15:32:24 +0800 Subject: [PATCH 05/57] esp-tls: Changed default behaviour for esp-tls client ( for security purpose) Commit ID: ca964dfb --- components/esp-tls/Kconfig | 19 +++++++++++++++++++ components/esp-tls/esp_tls_mbedtls.c | 5 +++++ components/esp-tls/esp_tls_wolfssl.c | 5 +++++ 3 files changed, 29 insertions(+) diff --git a/components/esp-tls/Kconfig b/components/esp-tls/Kconfig index dc9154170..e61145974 100644 --- a/components/esp-tls/Kconfig +++ b/components/esp-tls/Kconfig @@ -31,6 +31,25 @@ menu "ESP-TLS" Enable support for pre shared key ciphers, supported for both mbedTLS as well as wolfSSL TLS library. + config ESP_TLS_INSECURE + bool "Allow potentially insecure options" + help + You can enable some potentially insecure options. These options should only be used for testing pusposes. + Only enable these options if you are very sure. + + config ESP_TLS_SKIP_SERVER_CERT_VERIFY + bool "Skip server certificate verification by default (WARNING: ONLY FOR TESTING PURPOSE, READ HELP)" + depends on ESP_TLS_INSECURE + help + After enabling this option the esp-tls client will skip the server certificate verification + by default. Note that this option will only modify the default behaviour of esp-tls client + regarding server cert verification. The default behaviour should only be applicable when + no other option regarding the server cert verification is opted in the esp-tls config + (e.g. crt_bundle_attach, use_global_ca_store etc.). + WARNING : Enabling this option comes with a potential risk of establishing a TLS connection + with a server which has a fake identity, provided that the server certificate + is not provided either through API or other mechanism like ca_store etc. + config ESP_WOLFSSL_SMALL_CERT_VERIFY bool "Enable SMALL_CERT_VERIFY" depends on ESP_TLS_USING_WOLFSSL diff --git a/components/esp-tls/esp_tls_mbedtls.c b/components/esp-tls/esp_tls_mbedtls.c index 245921fd0..9a7a45e69 100644 --- a/components/esp-tls/esp_tls_mbedtls.c +++ b/components/esp-tls/esp_tls_mbedtls.c @@ -445,7 +445,12 @@ esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t return ESP_ERR_INVALID_STATE; #endif } else { +#ifdef CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); +#else + ESP_LOGE(TAG, "No server verification option set in esp_tls_cfg_t structure. Check esp_tls API reference"); + return ESP_ERR_MBEDTLS_SSL_SETUP_FAILED; +#endif } if (cfg->clientcert_buf != NULL && cfg->clientkey_buf != NULL) { diff --git a/components/esp-tls/esp_tls_wolfssl.c b/components/esp-tls/esp_tls_wolfssl.c index 7ec5ee383..7a1867a62 100644 --- a/components/esp-tls/esp_tls_wolfssl.c +++ b/components/esp-tls/esp_tls_wolfssl.c @@ -201,7 +201,12 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls return ESP_ERR_INVALID_STATE; #endif } else { +#ifdef CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY wolfSSL_CTX_set_verify( (WOLFSSL_CTX *)tls->priv_ctx, WOLFSSL_VERIFY_NONE, NULL); +#else + ESP_LOGE(TAG, "No server verification option set in esp_tls_cfg_t structure. Check esp_tls API reference"); + return ESP_ERR_WOLFSSL_SSL_SETUP_FAILED; +#endif } if (cfg->clientcert_buf != NULL && cfg->clientkey_buf != NULL) { From 99771fa7e2c2e25c3a8ceef0ceb40ca848c5527e Mon Sep 17 00:00:00 2001 From: yuanjm Date: Fri, 12 Mar 2021 14:10:06 +0800 Subject: [PATCH 06/57] fix(mbedtls): Fix mbedtls_ssl_send_alert_message crash due to ssl->out_iv is NULL --- .../port/dynamic/esp_mbedtls_dynamic_impl.c | 173 ++++++++++-------- .../port/dynamic/esp_mbedtls_dynamic_impl.h | 15 ++ components/mbedtls/port/dynamic/esp_ssl_tls.c | 4 +- 3 files changed, 114 insertions(+), 78 deletions(-) diff --git a/components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.c b/components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.c index e78ea5afe..f64b09e35 100644 --- a/components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.c +++ b/components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.c @@ -23,6 +23,33 @@ static const char *TAG = "Dynamic Impl"; +static void esp_mbedtls_set_buf_state(unsigned char *buf, esp_mbedtls_ssl_buf_states state) +{ + struct esp_mbedtls_ssl_buf *temp = __containerof(buf, struct esp_mbedtls_ssl_buf, buf[0]); + temp->state = state; +} + +static esp_mbedtls_ssl_buf_states esp_mbedtls_get_buf_state(unsigned char *buf) +{ + struct esp_mbedtls_ssl_buf *temp = __containerof(buf, struct esp_mbedtls_ssl_buf, buf[0]); + return temp->state; +} + +void esp_mbedtls_free_buf(unsigned char *buf) +{ + struct esp_mbedtls_ssl_buf *temp = __containerof(buf, struct esp_mbedtls_ssl_buf, buf[0]); + ESP_LOGV(TAG, "free buffer @ %p", temp); + mbedtls_free(temp); +} + +static void esp_mbedtls_init_ssl_buf(struct esp_mbedtls_ssl_buf *buf, unsigned int len) +{ + if (buf) { + buf->state = ESP_MBEDTLS_SSL_BUF_CACHED; + buf->len = len; + } +} + static void esp_mbedtls_parse_record_header(mbedtls_ssl_context *ssl) { ssl->in_msgtype = ssl->in_hdr[0]; @@ -118,29 +145,30 @@ static void init_rx_buffer(mbedtls_ssl_context *ssl, unsigned char *buf) static int esp_mbedtls_alloc_tx_buf(mbedtls_ssl_context *ssl, int len) { - unsigned char *buf; + struct esp_mbedtls_ssl_buf *esp_buf; if (ssl->out_buf) { - mbedtls_free(ssl->out_buf); + esp_mbedtls_free_buf(ssl->out_buf); ssl->out_buf = NULL; } - buf = mbedtls_calloc(1, len); - if (!buf) { - ESP_LOGE(TAG, "alloc(%d bytes) failed", len); + esp_buf = mbedtls_calloc(1, SSL_BUF_HEAD_OFFSET_SIZE + len); + if (!esp_buf) { + ESP_LOGE(TAG, "alloc(%d bytes) failed", SSL_BUF_HEAD_OFFSET_SIZE + len); return MBEDTLS_ERR_SSL_ALLOC_FAILED; } - ESP_LOGV(TAG, "add out buffer %d bytes @ %p", len, buf); + ESP_LOGV(TAG, "add out buffer %d bytes @ %p", len, esp_buf->buf); + esp_mbedtls_init_ssl_buf(esp_buf, len); /** * Mark the out_msg offset from ssl->out_buf. - * + * * In mbedtls, ssl->out_msg = ssl->out_buf + offset; */ ssl->out_msg = (unsigned char *)MBEDTLS_SSL_HEADER_LEN; - init_tx_buffer(ssl, buf); + init_tx_buffer(ssl, esp_buf->buf); return 0; } @@ -150,7 +178,7 @@ int esp_mbedtls_setup_tx_buffer(mbedtls_ssl_context *ssl) CHECK_OK(esp_mbedtls_alloc_tx_buf(ssl, TX_IDLE_BUFFER_SIZE)); /* mark the out buffer has no data cached */ - ssl->out_iv = NULL; + esp_mbedtls_set_buf_state(ssl->out_buf, ESP_MBEDTLS_SSL_BUF_NO_CACHED); return 0; } @@ -168,10 +196,7 @@ int esp_mbedtls_reset_add_tx_buffer(mbedtls_ssl_context *ssl) int esp_mbedtls_reset_free_tx_buffer(mbedtls_ssl_context *ssl) { - ESP_LOGV(TAG, "free out buffer @ %p", ssl->out_buf); - - mbedtls_free(ssl->out_buf); - + esp_mbedtls_free_buf(ssl->out_buf); init_tx_buffer(ssl, NULL); CHECK_OK(esp_mbedtls_setup_tx_buffer(ssl)); @@ -181,60 +206,57 @@ int esp_mbedtls_reset_free_tx_buffer(mbedtls_ssl_context *ssl) int esp_mbedtls_reset_add_rx_buffer(mbedtls_ssl_context *ssl) { - unsigned char *buf; + struct esp_mbedtls_ssl_buf *esp_buf; if (ssl->in_buf) { - mbedtls_free(ssl->in_buf); + esp_mbedtls_free_buf(ssl->in_buf); ssl->in_buf = NULL; } - buf = mbedtls_calloc(1, MBEDTLS_SSL_IN_BUFFER_LEN); - if (!buf) { - ESP_LOGE(TAG, "alloc(%d bytes) failed", MBEDTLS_SSL_IN_BUFFER_LEN); + esp_buf = mbedtls_calloc(1, SSL_BUF_HEAD_OFFSET_SIZE + MBEDTLS_SSL_IN_BUFFER_LEN); + if (!esp_buf) { + ESP_LOGE(TAG, "alloc(%d bytes) failed", SSL_BUF_HEAD_OFFSET_SIZE + MBEDTLS_SSL_IN_BUFFER_LEN); return MBEDTLS_ERR_SSL_ALLOC_FAILED; } - ESP_LOGV(TAG, "add in buffer %d bytes @ %p", MBEDTLS_SSL_IN_BUFFER_LEN, buf); + ESP_LOGV(TAG, "add in buffer %d bytes @ %p", MBEDTLS_SSL_IN_BUFFER_LEN, esp_buf->buf); + esp_mbedtls_init_ssl_buf(esp_buf, MBEDTLS_SSL_IN_BUFFER_LEN); /** * Mark the in_msg offset from ssl->in_buf. - * + * * In mbedtls, ssl->in_msg = ssl->in_buf + offset; */ ssl->in_msg = (unsigned char *)MBEDTLS_SSL_HEADER_LEN; - init_rx_buffer(ssl, buf); + init_rx_buffer(ssl, esp_buf->buf); - return 0; + return 0; } void esp_mbedtls_reset_free_rx_buffer(mbedtls_ssl_context *ssl) { - ESP_LOGV(TAG, "free in buffer @ %p", ssl->in_buf); - - mbedtls_free(ssl->in_buf); - - init_rx_buffer(ssl, NULL); + esp_mbedtls_free_buf(ssl->in_buf); + init_rx_buffer(ssl, NULL); } int esp_mbedtls_add_tx_buffer(mbedtls_ssl_context *ssl, size_t buffer_len) { int ret = 0; int cached = 0; - unsigned char *buf; + struct esp_mbedtls_ssl_buf *esp_buf; unsigned char cache_buf[CACHE_BUFFER_SIZE]; ESP_LOGV(TAG, "--> add out"); if (ssl->out_buf) { - if (ssl->out_iv) { + if (esp_mbedtls_get_buf_state(ssl->out_buf) == ESP_MBEDTLS_SSL_BUF_CACHED) { ESP_LOGV(TAG, "out buffer is not empty"); ret = 0; goto exit; } else { memcpy(cache_buf, ssl->out_buf, CACHE_BUFFER_SIZE); - - mbedtls_free(ssl->out_buf); + esp_mbedtls_free_buf(ssl->out_buf); init_tx_buffer(ssl, NULL); cached = 1; } @@ -242,15 +264,17 @@ int esp_mbedtls_add_tx_buffer(mbedtls_ssl_context *ssl, size_t buffer_len) buffer_len = tx_buffer_len(ssl, buffer_len); - buf = mbedtls_calloc(1, buffer_len); - if (!buf) { - ESP_LOGE(TAG, "alloc(%d bytes) failed", buffer_len); + esp_buf = mbedtls_calloc(1, SSL_BUF_HEAD_OFFSET_SIZE + buffer_len); + if (!esp_buf) { + ESP_LOGE(TAG, "alloc(%d bytes) failed", SSL_BUF_HEAD_OFFSET_SIZE + buffer_len); ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; goto exit; } - ESP_LOGV(TAG, "add out buffer %d bytes @ %p", buffer_len, buf); - init_tx_buffer(ssl, buf); + ESP_LOGV(TAG, "add out buffer %d bytes @ %p", buffer_len, esp_buf->buf); + + esp_mbedtls_init_ssl_buf(esp_buf, buffer_len); + init_tx_buffer(ssl, esp_buf->buf); if (cached) { memcpy(ssl->out_ctr, cache_buf, COUNTER_SIZE); @@ -270,11 +294,11 @@ int esp_mbedtls_free_tx_buffer(mbedtls_ssl_context *ssl) { int ret = 0; unsigned char buf[CACHE_BUFFER_SIZE]; - unsigned char *pdata; + struct esp_mbedtls_ssl_buf *esp_buf; ESP_LOGV(TAG, "--> free out"); - if (!ssl->out_buf || (ssl->out_buf && !ssl->out_iv)) { + if (!ssl->out_buf || (ssl->out_buf && (esp_mbedtls_get_buf_state(ssl->out_buf) == ESP_MBEDTLS_SSL_BUF_NO_CACHED))) { ret = 0; goto exit; } @@ -282,22 +306,19 @@ int esp_mbedtls_free_tx_buffer(mbedtls_ssl_context *ssl) memcpy(buf, ssl->out_ctr, COUNTER_SIZE); memcpy(buf + COUNTER_SIZE, ssl->out_iv, CACHE_IV_SIZE); - ESP_LOGV(TAG, "free out buffer @ %p", ssl->out_buf); - - mbedtls_free(ssl->out_buf); - + esp_mbedtls_free_buf(ssl->out_buf); init_tx_buffer(ssl, NULL); - pdata = mbedtls_calloc(1, TX_IDLE_BUFFER_SIZE); - if (!pdata) { - ESP_LOGE(TAG, "alloc(%d bytes) failed", TX_IDLE_BUFFER_SIZE); + esp_buf = mbedtls_calloc(1, SSL_BUF_HEAD_OFFSET_SIZE + TX_IDLE_BUFFER_SIZE); + if (!esp_buf) { + ESP_LOGE(TAG, "alloc(%d bytes) failed", SSL_BUF_HEAD_OFFSET_SIZE + TX_IDLE_BUFFER_SIZE); return MBEDTLS_ERR_SSL_ALLOC_FAILED; } - memcpy(pdata, buf, CACHE_BUFFER_SIZE); - init_tx_buffer(ssl, pdata); - ssl->out_iv = NULL; - + esp_mbedtls_init_ssl_buf(esp_buf, TX_IDLE_BUFFER_SIZE); + memcpy(esp_buf->buf, buf, CACHE_BUFFER_SIZE); + init_tx_buffer(ssl, esp_buf->buf); + esp_mbedtls_set_buf_state(ssl->out_buf, ESP_MBEDTLS_SSL_BUF_NO_CACHED); exit: ESP_LOGV(TAG, "<-- free out"); @@ -309,7 +330,7 @@ int esp_mbedtls_add_rx_buffer(mbedtls_ssl_context *ssl) int cached = 0; int ret = 0; int buffer_len; - unsigned char *buf; + struct esp_mbedtls_ssl_buf *esp_buf; unsigned char cache_buf[16]; unsigned char msg_head[5]; size_t in_msglen, in_left; @@ -317,15 +338,11 @@ int esp_mbedtls_add_rx_buffer(mbedtls_ssl_context *ssl) ESP_LOGV(TAG, "--> add rx"); if (ssl->in_buf) { - if (ssl->in_iv) { + if (esp_mbedtls_get_buf_state(ssl->in_buf) == ESP_MBEDTLS_SSL_BUF_CACHED) { ESP_LOGV(TAG, "in buffer is not empty"); ret = 0; goto exit; } else { - memcpy(cache_buf, ssl->in_buf, 16); - - mbedtls_free(ssl->in_buf); - init_rx_buffer(ssl, NULL); cached = 1; } } @@ -341,7 +358,7 @@ int esp_mbedtls_add_rx_buffer(mbedtls_ssl_context *ssl) } else { ESP_LOGE(TAG, "mbedtls_ssl_fetch_input error=-0x%x", -ret); } - + goto exit; } @@ -354,16 +371,23 @@ int esp_mbedtls_add_rx_buffer(mbedtls_ssl_context *ssl) ESP_LOGV(TAG, "message length is %d RX buffer length should be %d left is %d", (int)in_msglen, (int)buffer_len, (int)ssl->in_left); - buf = mbedtls_calloc(1, buffer_len); - if (!buf) { - ESP_LOGE(TAG, "alloc(%d bytes) failed", buffer_len); + if (cached) { + memcpy(cache_buf, ssl->in_buf, 16); + esp_mbedtls_free_buf(ssl->in_buf); + init_rx_buffer(ssl, NULL); + } + + esp_buf = mbedtls_calloc(1, SSL_BUF_HEAD_OFFSET_SIZE + buffer_len); + if (!esp_buf) { + ESP_LOGE(TAG, "alloc(%d bytes) failed", SSL_BUF_HEAD_OFFSET_SIZE + buffer_len); ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; goto exit; } - ESP_LOGV(TAG, "add in buffer %d bytes @ %p", buffer_len, buf); + ESP_LOGV(TAG, "add in buffer %d bytes @ %p", buffer_len, esp_buf->buf); - init_rx_buffer(ssl, buf); + esp_mbedtls_init_ssl_buf(esp_buf, buffer_len); + init_rx_buffer(ssl, esp_buf->buf); if (cached) { memcpy(ssl->in_ctr, cache_buf, 8); @@ -377,14 +401,14 @@ int esp_mbedtls_add_rx_buffer(mbedtls_ssl_context *ssl) exit: ESP_LOGV(TAG, "<-- add rx"); - return ret; + return ret; } int esp_mbedtls_free_rx_buffer(mbedtls_ssl_context *ssl) { int ret = 0; unsigned char buf[16]; - unsigned char *pdata; + struct esp_mbedtls_ssl_buf *esp_buf; ESP_LOGV(TAG, "--> free rx"); @@ -392,7 +416,7 @@ int esp_mbedtls_free_rx_buffer(mbedtls_ssl_context *ssl) * When have read multi messages once, can't free the input buffer directly. */ if (!ssl->in_buf || (ssl->in_hslen && (ssl->in_hslen < ssl->in_msglen)) || - (ssl->in_buf && !ssl->in_iv)) { + (ssl->in_buf && (esp_mbedtls_get_buf_state(ssl->in_buf) == ESP_MBEDTLS_SSL_BUF_NO_CACHED))) { ret = 0; goto exit; } @@ -407,23 +431,20 @@ int esp_mbedtls_free_rx_buffer(mbedtls_ssl_context *ssl) memcpy(buf, ssl->in_ctr, 8); memcpy(buf + 8, ssl->in_iv, 8); - ESP_LOGV(TAG, "free in buffer @ %p", ssl->out_buf); - - mbedtls_free(ssl->in_buf); - + esp_mbedtls_free_buf(ssl->in_buf); init_rx_buffer(ssl, NULL); - pdata = mbedtls_calloc(1, 16); - if (!pdata) { - ESP_LOGE(TAG, "alloc(%d bytes) failed", 16); + esp_buf = mbedtls_calloc(1, SSL_BUF_HEAD_OFFSET_SIZE + 16); + if (!esp_buf) { + ESP_LOGE(TAG, "alloc(%d bytes) failed", SSL_BUF_HEAD_OFFSET_SIZE + 16); ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; goto exit; } - memcpy(pdata, buf, 16); - init_rx_buffer(ssl, pdata); - ssl->in_iv = NULL; - + esp_mbedtls_init_ssl_buf(esp_buf, 16); + memcpy(esp_buf->buf, buf, 16); + init_rx_buffer(ssl, esp_buf->buf); + esp_mbedtls_set_buf_state(ssl->in_buf, ESP_MBEDTLS_SSL_BUF_NO_CACHED); exit: ESP_LOGV(TAG, "<-- free rx"); @@ -438,7 +459,7 @@ size_t esp_mbedtls_get_crt_size(mbedtls_x509_crt *cert, size_t *num) while (cert) { bytes += cert->raw.len; n++; - + cert = cert->next; } diff --git a/components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.h b/components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.h index 8f4bb144c..2c6b15c00 100644 --- a/components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.h +++ b/components/mbedtls/port/dynamic/esp_mbedtls_dynamic_impl.h @@ -41,6 +41,21 @@ \ }) +typedef enum { + ESP_MBEDTLS_SSL_BUF_CACHED, + ESP_MBEDTLS_SSL_BUF_NO_CACHED, +} esp_mbedtls_ssl_buf_states; + +struct esp_mbedtls_ssl_buf { + esp_mbedtls_ssl_buf_states state; + unsigned int len; + unsigned char buf[]; +}; + +#define SSL_BUF_HEAD_OFFSET_SIZE offsetof(struct esp_mbedtls_ssl_buf, buf) + +void esp_mbedtls_free_buf(unsigned char *buf); + int esp_mbedtls_setup_tx_buffer(mbedtls_ssl_context *ssl); void esp_mbedtls_setup_rx_buffer(mbedtls_ssl_context *ssl); diff --git a/components/mbedtls/port/dynamic/esp_ssl_tls.c b/components/mbedtls/port/dynamic/esp_ssl_tls.c index 081e50af8..d8b4506b5 100644 --- a/components/mbedtls/port/dynamic/esp_ssl_tls.c +++ b/components/mbedtls/port/dynamic/esp_ssl_tls.c @@ -108,12 +108,12 @@ int __wrap_mbedtls_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, size_t void __wrap_mbedtls_ssl_free(mbedtls_ssl_context *ssl) { if (ssl->out_buf) { - mbedtls_free(ssl->out_buf); + esp_mbedtls_free_buf(ssl->out_buf); ssl->out_buf = NULL; } if (ssl->in_buf) { - mbedtls_free(ssl->in_buf); + esp_mbedtls_free_buf(ssl->in_buf); ssl->in_buf = NULL; } From e59e48fd6dd11340d12bdf1bdfade92946cde30e Mon Sep 17 00:00:00 2001 From: yuanjm Date: Tue, 27 Apr 2021 14:39:50 +0800 Subject: [PATCH 07/57] tcpip_adapter: fix set static ip fail and remove the dhcp_check timer --- components/tcpip_adapter/tcpip_adapter_lwip.c | 84 +++++-------------- 1 file changed, 21 insertions(+), 63 deletions(-) diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index d3a31d635..bf3f8bad9 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -74,7 +74,6 @@ static esp_err_t tcpip_adapter_reset_ip_info(tcpip_adapter_if_t tcpip_if); static esp_err_t tcpip_adapter_start_ip_lost_timer(tcpip_adapter_if_t tcpip_if); static void tcpip_adapter_dhcpc_cb(struct netif *netif); static void tcpip_adapter_ip_lost_timer(void *arg); -static void tcpip_adapter_dhcpc_done(TimerHandle_t arg); static bool tcpip_inited = false; static const char* TAG = "tcpip_adapter"; @@ -85,9 +84,25 @@ ESP_EVENT_DEFINE_BASE(IP_EVENT); err_t ethernetif_init(struct netif* netif); void system_station_got_ip_set(); -static int dhcp_fail_time = 0; static tcpip_adapter_ip_info_t esp_ip[TCPIP_ADAPTER_IF_MAX]; -static TimerHandle_t *dhcp_check_timer; + +static void tcpip_adapter_set_wifi_ps(bool flag) +{ + static bool is_ps_set = false; + if (flag) { + if (!is_ps_set) { + ESP_LOGD(TAG, "enable wifi ps"); + esp_wifi_ps_lock(); + is_ps_set = true; + } + } else { + if (is_ps_set) { + ESP_LOGD(TAG, "disable wifi ps"); + esp_wifi_ps_unlock(); + is_ps_set = false; + } + } +} static void tcpip_adapter_dhcps_cb(u8_t client_ip[4]) { @@ -192,11 +207,6 @@ void tcpip_adapter_init(void) IP4_ADDR(&esp_ip[TCPIP_ADAPTER_IF_AP].ip, 192, 168 , 4, 1); IP4_ADDR(&esp_ip[TCPIP_ADAPTER_IF_AP].gw, 192, 168 , 4, 1); IP4_ADDR(&esp_ip[TCPIP_ADAPTER_IF_AP].netmask, 255, 255 , 255, 0); - - dhcp_check_timer = xTimerCreate("check_dhcp", 500 / portTICK_RATE_MS, true, NULL, tcpip_adapter_dhcpc_done); - if (!dhcp_check_timer) { - ESP_LOGI(TAG, "TCPIP adapter timer create error"); - } } } @@ -287,56 +297,6 @@ static int tcpip_adapter_sta_recv_cb(void *buffer, uint16_t len, void *eb) return tcpip_adapter_recv_cb(esp_netif[ESP_IF_WIFI_STA], buffer, len, eb); } -static void tcpip_adapter_dhcpc_done(TimerHandle_t xTimer) -{ - bool unlock_ps = true; - struct dhcp *clientdhcp = netif_dhcp_data(esp_netif[TCPIP_ADAPTER_IF_STA]) ; - struct netif *netif = esp_netif[TCPIP_ADAPTER_IF_STA]; - - if (!netif) { - ESP_LOGD(TAG, "null netif=%p", netif); - return; - } - -#if LWIP_IPV4 && LWIP_AUTOIP - struct autoip *autoip = netif_autoip_data(netif); -#endif - - xTimerStop(dhcp_check_timer, 0); - if (netif_is_up(esp_netif[TCPIP_ADAPTER_IF_STA])) { - if ((clientdhcp && clientdhcp->state == DHCP_STATE_BOUND) -#if LWIP_IPV4 && LWIP_AUTOIP - || (autoip && autoip->state == AUTOIP_STATE_ANNOUNCING) -#endif - ) { - /*send event here*/ - tcpip_adapter_dhcpc_cb(esp_netif[TCPIP_ADAPTER_IF_STA]); - ESP_LOGD(TAG,"ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR "\n", IP2STR(ip_2_ip4(&(esp_netif[0]->ip_addr))), - IP2STR(ip_2_ip4(&(esp_netif[0]->netmask))), IP2STR(ip_2_ip4(&(esp_netif[0]->gw)))); - dhcp_fail_time = 0; - } else if (dhcp_fail_time < (CONFIG_IP_LOST_TIMER_INTERVAL * 1000 / 500)) { - ESP_LOGD(TAG,"dhcpc time(ms): %d\n", dhcp_fail_time * 500); - dhcp_fail_time ++; - xTimerReset(dhcp_check_timer, 0); - unlock_ps = false; - } else { - dhcp_fail_time = 0; - ESP_LOGD(TAG,"ERROR dhcp get ip error\n"); - } - } else { - dhcp_fail_time = 0; - tcpip_adapter_release_dhcp(esp_netif[TCPIP_ADAPTER_IF_STA]); - - dhcpc_status[TCPIP_ADAPTER_IF_STA] = TCPIP_ADAPTER_DHCP_INIT; - - tcpip_adapter_reset_ip_info(TCPIP_ADAPTER_IF_STA); - } - - if (unlock_ps) { - esp_wifi_ps_unlock(); - } -} - static esp_err_t tcpip_adapter_update_default_netif(void) { if ((esp_netif[TCPIP_ADAPTER_IF_STA] != NULL) && netif_is_up(esp_netif[TCPIP_ADAPTER_IF_STA])) { @@ -1073,6 +1033,7 @@ static void tcpip_adapter_dhcpc_cb(struct netif *netif) } } + tcpip_adapter_set_wifi_ps(false); return; } @@ -1171,16 +1132,13 @@ esp_err_t tcpip_adapter_dhcpc_start(tcpip_adapter_if_t tcpip_if) return ESP_OK; } - esp_wifi_ps_lock(); + tcpip_adapter_set_wifi_ps(true); if (tcpip_adapter_start_dhcp(p_netif) != ERR_OK) { - esp_wifi_ps_unlock(); + tcpip_adapter_set_wifi_ps(false); ESP_LOGD(TAG, "dhcp client start failed"); return ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED; } - - dhcp_fail_time = 0; - xTimerReset(dhcp_check_timer, portMAX_DELAY); ESP_LOGD(TAG, "dhcp client start successfully"); dhcpc_status[tcpip_if] = TCPIP_ADAPTER_DHCP_STARTED; return ESP_OK; From 38011372cd3b00891ed603e8db034f34258ae1fd Mon Sep 17 00:00:00 2001 From: Chen Wu Date: Wed, 28 Apr 2021 11:56:21 +0800 Subject: [PATCH 08/57] fix: potential blocking code when call uart_wait_tx_done() 1. there is a risk of ticks_end overflow, if xTaskGetTickCount() plus ticks_to_wait is bigger than portMAX_DELAY 2. potential blocking code on waiting for tx fifo done. It usually occurs at esp uart uses flow control, and the other side of uart not. --- components/esp8266/driver/uart.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/components/esp8266/driver/uart.c b/components/esp8266/driver/uart.c index 63d2a92bb..ae067dd07 100644 --- a/components/esp8266/driver/uart.c +++ b/components/esp8266/driver/uart.c @@ -257,7 +257,18 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait) uint32_t baudrate; uint32_t byte_delay_us = 0; BaseType_t res; + portTickType ticks_cur; + portTickType ticks_start = xTaskGetTickCount(); portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait; + /** + * Considering the overflow of the ticks_end and the ticks_cur (xTaskGetTickCount()), + * the possible tick timestamp is as follows: + * (one start tick timestamp, two end tick timestamps, four current tick timestamps) + * + * ticks: 0 0xFFFFFFFF + * |_______._______._______._______._______._______._______._______| + * cur1 end1 cur2 start cur3 end2 cur4 + */ // Take tx_mux res = xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)ticks_to_wait); @@ -273,10 +284,22 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait) uart_get_baudrate(uart_num, &baudrate); byte_delay_us = (uint32_t)(10000000 / baudrate); // (1/baudrate)*10*1000_000 us - ticks_to_wait = ticks_end - xTaskGetTickCount(); + ticks_cur = xTaskGetTickCount(); + if (ticks_start <= ticks_cur) { + ticks_to_wait = ticks_to_wait - (ticks_cur - ticks_start); + } else { + ticks_to_wait = ticks_to_wait - (portMAX_DELAY - ticks_start + ticks_cur); + } // wait for tx done sem. if (pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, ticks_to_wait)) { while (1) { + ticks_cur = xTaskGetTickCount(); + bool end1_timeout = (ticks_end < ticks_start && ticks_cur < ticks_start && ticks_cur > ticks_end); + bool end2_timeout = (ticks_start < ticks_end && (ticks_cur < ticks_start || ticks_end < ticks_cur)); + if (end1_timeout || end2_timeout) { + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + return ESP_ERR_TIMEOUT; + } if (UART[uart_num]->status.txfifo_cnt == 0) { ets_delay_us(byte_delay_us); // Delay one byte time to guarantee transmission completion break; From a2ed0747a1246c8c0ed0b42bcf569fe263972341 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 4 May 2021 19:00:39 +1000 Subject: [PATCH 09/57] freertos: Add queue init overflow check Based on FreeRTOS kernel patch 47338393 but modified to work without assertions. --- components/freertos/freertos/queue.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/components/freertos/freertos/queue.c b/components/freertos/freertos/queue.c index c37d285f3..a87d6d62e 100644 --- a/components/freertos/freertos/queue.c +++ b/components/freertos/freertos/queue.c @@ -360,6 +360,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; Queue_t *pxNewQueue; size_t xQueueSizeInBytes; uint8_t *pucQueueStorage; + BaseType_t overflow; configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); @@ -375,7 +376,29 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ } - pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); + /* Check for multiplication overflow. */ + overflow = ( uxItemSize != 0 ) && ( uxQueueLength != ( xQueueSizeInBytes / uxItemSize ) ); + + /* Check for addition overflow. */ + overflow = overflow || ( ( sizeof( Queue_t ) + xQueueSizeInBytes ) < xQueueSizeInBytes ); + + if ( overflow == (BaseType_t) 0 ) + { + /* Allocate the queue and storage area. Justification for MISRA + deviation as follows: pvPortMalloc() always ensures returned memory + blocks are aligned per the requirements of the MCU stack. In this case + pvPortMalloc() must return a pointer that is guaranteed to meet the + alignment requirements of the Queue_t structure - which in this case + is an int8_t *. Therefore, whenever the stack alignment requirements + are greater than or equal to the pointer to char requirements the cast + is safe. In other cases alignment requirements are not strict (one or + two bytes). */ + pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); /*lint !e9087 !e9079 see comment above. */ + } + else + { + pxNewQueue = NULL; + } if( pxNewQueue != NULL ) { From f4f212aa6ef37d81bb41e950b288b1ee1a8af9cb Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 4 May 2021 19:03:58 +1000 Subject: [PATCH 10/57] freertos: Add addition overflow check for stream buffer Patch from upstream commit d05b9c123f2bf9090bce386a244fc934ae44db5b --- components/freertos/freertos/stream_buffer.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/components/freertos/freertos/stream_buffer.c b/components/freertos/freertos/stream_buffer.c index c60045f69..317be2355 100644 --- a/components/freertos/freertos/stream_buffer.c +++ b/components/freertos/freertos/stream_buffer.c @@ -242,8 +242,15 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, this is a quirk of the implementation that means otherwise the free space would be reported as one byte smaller than would be logically expected. */ - xBufferSizeBytes++; - pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */ + if( xBufferSizeBytes < ( xBufferSizeBytes + 1 + sizeof( StreamBuffer_t ) ) ) + { + xBufferSizeBytes++; + pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */ + } + else + { + pucAllocatedMemory = NULL; + } if( pucAllocatedMemory != NULL ) { From 53f2bc65e4f5a3262792023580eb4ffaa1992ccd Mon Sep 17 00:00:00 2001 From: Chen Wu Date: Wed, 12 May 2021 19:38:23 +0800 Subject: [PATCH 11/57] fix(lib): fix beacon ie error when set to bgn mode --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libnet80211.a | Bin 484932 -> 484912 bytes components/esp8266/lib/libnet80211_dbg.a | Bin 536908 -> 536888 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index b2c4332be..97aa97f42 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,6 +1,6 @@ gwen: core: cebfb0e - net80211: 8114f9c + net80211: 074988c pp: 5fda74f espnow: 7a93d71 diff --git a/components/esp8266/lib/libnet80211.a b/components/esp8266/lib/libnet80211.a index ed88b9dcbe91c5dc69945b76bfdb33ab7ce45b3d..1a72f88f0fe71ac08c8758f8f378fc9902c88757 100755 GIT binary patch delta 3069 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 delta 3200 zcmc(hTTC2f6vxk*nPn-|7Ip~>EzsRXU>hkcNTF*nTm*xL(qh!`&<4qnj$GFiP6+hBz1V9f#`!KrizyrFNrj*LDLx5^g+|mdcI|tT`B^tAx`q= z{O5PhcfQNQw@h5Oe}3KGyCpm;D?7`blecrs*^lZmz@D{Bk^u}wTmor1#VH`IRqA4) zX9T2Bl~#fDUvz2$qz+!-qPkrmEhBX~_^?cl?}a6D90qx1sjC(IGe1-Y@@g8L19?qS z|GiLwZ(!Y}wtWK1|0s2($xZv+u+CD~dxBN^t83h$|5Grnht&0G`T#xEb=lS07r>wY z+KX4LHCNWa1FP}CEigAeoWhd|VHNpWcPIINE!s9-8h$0i_}-zrUdc8dpLa9XK)y}q zW5*LJUQAs|dXF^*$@r%8t%*zXmnOanex1=ZzsWZK&ez}CjUvkEmTZbAH^=RBRHWgd z@yXlGTO}!;@}lr()rB~4ZwesW0Zvrx$*s;>aAp?gz3FllrCO4mnU3rWQ)%)RrvrX3 zuw%EVWy4k2B|Mw#^le=iIggzNa1B0HW*tB#}8sMzVHPC#8?2_JWlw?-E8=|q4Oy2`AdlZBgE%$9o7ZP z;f~G)yF;_DpiMRNP|>pj^99<#4kaJkg zKlpiE=Y_hDtcGU=hhjY;>n8U&1-m_gbNI!GvEtgM&IR(5CCK$&Pd6IgL%Yk;YEr zUTh~k!=Z&LML0~uB2ww)yZGE4j}yjiI8mOn0OKYzWX+L3623&~m1Vudm-qUkX}IvrMJ(G~dv< zSh9CB>Y%J{E}Y`R%Yotbf(}v}Q$E7?L>QqN4q-WY09V6&cN?5|n;bnns-zTPg#2xi zm1=s>68r=IZB({teLZ-j!C-us*tA4h+94ZA6E}`TuZ2s|OIWPbKcz%O)gL;M@kVA= z?&3ejfontiEJE@;Vw4AN7tIkTwK;+;F#EJe>W?&-_EM=-^M7}#$#`8{TY^kC zz4tA~B^hNJ-&-|a Date: Fri, 7 May 2021 11:33:30 +0800 Subject: [PATCH 12/57] fix(sc): fix the issue of sending failure and exit 1. Send unicast first, use broadcast to send if unicast fails. 2. Send 60 times successfully before exiting. --- components/esp8266/source/smartconfig_ack.c | 41 +++++++++---------- .../wifi/smart_config/main/Kconfig.projbuild | 4 +- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/components/esp8266/source/smartconfig_ack.c b/components/esp8266/source/smartconfig_ack.c index a71b62f3a..4610cea0e 100644 --- a/components/esp8266/source/smartconfig_ack.c +++ b/components/esp8266/source/smartconfig_ack.c @@ -79,7 +79,7 @@ static void sc_ack_send_task(void* pvParameters) sc_ack_t* ack = (sc_ack_t*)pvParameters; tcpip_adapter_ip_info_t local_ip; uint8_t remote_ip[4]; - memset(remote_ip, 0xFF, sizeof(remote_ip)); + memcpy(remote_ip, ack->ctx.ip, sizeof(remote_ip)); struct sockaddr_in server_addr; socklen_t sin_size = sizeof(server_addr); int send_sock = -1; @@ -99,6 +99,7 @@ static void sc_ack_send_task(void* pvParameters) port_bit = 0; } remote_port = SC_ACK_TOUCH_V2_SERVER_PORT(port_bit); + memset(remote_ip, 0xFF, sizeof(remote_ip)); } else { remote_port = SC_ACK_AIRKISS_SERVER_PORT; } @@ -156,35 +157,33 @@ static void sc_ack_send_task(void* pvParameters) memcpy(remote_ip, &from.sin_addr, 4); server_addr.sin_addr.s_addr = from.sin_addr.s_addr; } else { - goto _end; + server_addr.sin_addr.s_addr = INADDR_BROADCAST; } } + uint32_t ip_addr = server_addr.sin_addr.s_addr; while (s_sc_ack_send) { /* Send smartconfig ACK every 100ms. */ vTaskDelay(100 / portTICK_RATE_MS); - sendlen = sendto(send_sock, &ack->ctx, ack_len, 0, (struct sockaddr*) &server_addr, sin_size); - - if (sendlen > 0) { - /* Totally send 60 smartconfig ACKs. Then smartconfig is successful. */ - if (packet_count++ >= SC_ACK_MAX_COUNT) { - esp_event_post(SC_EVENT, SC_EVENT_SEND_ACK_DONE, NULL, 0, portMAX_DELAY); - goto _end; - } + if (ip_addr != INADDR_BROADCAST) { + sendto(send_sock, &ack->ctx, ack_len, 0, (struct sockaddr*) &server_addr, sin_size); + server_addr.sin_addr.s_addr = INADDR_BROADCAST; + sendlen = sendto(send_sock, &ack->ctx, ack_len, 0, (struct sockaddr*) &server_addr, sin_size); + server_addr.sin_addr.s_addr = ip_addr; } else { - err = sc_ack_send_get_errno(send_sock); - - if (err == ENOMEM || err == EAGAIN) { - ESP_LOGD(TAG, "send failed, errno %d", err); - continue; - } + sendlen = sendto(send_sock, &ack->ctx, ack_len, 0, (struct sockaddr*) &server_addr, sin_size); + } + if (sendlen <= 0) { + err = sc_ack_send_get_errno(send_sock); ESP_LOGE(TAG, "send failed, errno %d", err); - if ((send_sock >= LWIP_SOCKET_OFFSET) && (send_sock <= (FD_SETSIZE - 1))) { - close(send_sock); - } - send_sock = -1; - break; + vTaskDelay(200 / portTICK_RATE_MS); + } + + /* Send 60 smartconfig ACKs, exit regardless of failure or success. */ + if (packet_count++ >= SC_ACK_MAX_COUNT) { + esp_event_post(SC_EVENT, SC_EVENT_SEND_ACK_DONE, NULL, 0, portMAX_DELAY); + goto _end; } } } else { diff --git a/examples/wifi/smart_config/main/Kconfig.projbuild b/examples/wifi/smart_config/main/Kconfig.projbuild index 533a7140c..8d27ee8e0 100644 --- a/examples/wifi/smart_config/main/Kconfig.projbuild +++ b/examples/wifi/smart_config/main/Kconfig.projbuild @@ -12,7 +12,7 @@ config ESP_TOUCH bool "ESPTouch" config AIRKISS bool "AirKiss" -config ESP_TOUCH-AIRKISS +config ESP_TOUCH_AIRKISS bool "ESPTouch and AirKiss" config ESP_TOUCH_V2 bool "ESPTouch-V2" @@ -22,7 +22,7 @@ config ESP_SMARTCONFIG_TYPE int default 0 if ESP_TOUCH default 1 if AIRKISS - default 2 if ESP_TOUCH-AIRKISS + default 2 if ESP_TOUCH_AIRKISS default 3 if ESP_TOUCH_V2 endmenu From d1b44513bb481a13256a4ab6af7841dd4e3719a9 Mon Sep 17 00:00:00 2001 From: Chen Wen Date: Sat, 15 May 2021 17:49:12 +0800 Subject: [PATCH 13/57] feat(sc): Support ESP-Touch-V2 to send unicast --- components/esp8266/source/smartconfig_ack.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/components/esp8266/source/smartconfig_ack.c b/components/esp8266/source/smartconfig_ack.c index 4610cea0e..34bd8eb30 100644 --- a/components/esp8266/source/smartconfig_ack.c +++ b/components/esp8266/source/smartconfig_ack.c @@ -31,6 +31,7 @@ #include "esp_wifi.h" #include "esp_smartconfig.h" #include "smartconfig_ack.h" +#include "lwip/inet.h" #define SC_ACK_TASK_PRIORITY 2 /*!< Priority of sending smartconfig ACK task */ #define SC_ACK_TASK_STACK_SIZE 2048 /*!< Stack size of sending smartconfig ACK task */ @@ -40,7 +41,7 @@ #define SC_ACK_TOUCH_V2_SERVER_PORT(i) (18266+i*10000) /*!< ESP touch_v2 UDP port of server on cellphone */ #define SC_ACK_AIRKISS_SERVER_PORT 10000 /*!< Airkiss UDP port of server on cellphone */ #define SC_ACK_AIRKISS_DEVICE_PORT 10001 /*!< Airkiss UDP port of server on device */ -#define SC_ACK_AIRKISS_TIMEOUT 1500 /*!< Airkiss read data timout millisecond */ +#define SC_ACK_TIMEOUT 1500 /*!< Airkiss and ESP touch_v2 read data timout millisecond */ #define SC_ACK_TOUCH_LEN 11 /*!< Length of ESP touch ACK context */ #define SC_ACK_AIRKISS_LEN 7 /*!< Length of Airkiss ACK context */ @@ -133,21 +134,24 @@ static void sc_ack_send_task(void* pvParameters) setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, &optval, sizeof(int)); - if (ack->type == SC_TYPE_AIRKISS) { + if (ack->type == SC_TYPE_AIRKISS || ack->type == SC_TYPE_ESPTOUCH_V2) { char data = 0; struct sockaddr_in local_addr, from; socklen_t sockadd_len = sizeof(struct sockaddr); struct timeval timeout = { - SC_ACK_AIRKISS_TIMEOUT / 1000, - SC_ACK_AIRKISS_TIMEOUT % 1000 * 1000 + SC_ACK_TIMEOUT / 1000, + SC_ACK_TIMEOUT % 1000 * 1000 }; bzero(&local_addr, sizeof(struct sockaddr_in)); bzero(&from, sizeof(struct sockaddr_in)); local_addr.sin_family = AF_INET; local_addr.sin_addr.s_addr = INADDR_ANY; - local_addr.sin_port = htons(SC_ACK_AIRKISS_DEVICE_PORT); - + if (ack->type == SC_TYPE_AIRKISS) { + local_addr.sin_port = htons(SC_ACK_AIRKISS_DEVICE_PORT); + } else { + local_addr.sin_port = htons(SC_ACK_TOUCH_DEVICE_PORT); + } bind(send_sock, (struct sockaddr*)&local_addr, sockadd_len); setsockopt(send_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); @@ -156,6 +160,7 @@ static void sc_ack_send_task(void* pvParameters) if (from.sin_addr.s_addr != INADDR_ANY) { memcpy(remote_ip, &from.sin_addr, 4); server_addr.sin_addr.s_addr = from.sin_addr.s_addr; + ESP_LOGI(TAG, "cellphone_ip: %s", inet_ntoa(server_addr.sin_addr)); } else { server_addr.sin_addr.s_addr = INADDR_BROADCAST; } From 620605a39f83ec546d75c52bf42ae58ba552b46b Mon Sep 17 00:00:00 2001 From: Chen Wu Date: Tue, 18 May 2021 16:08:10 +0800 Subject: [PATCH 14/57] fix(lib): restart softap when phy mode change --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libnet80211.a | Bin 484912 -> 484912 bytes components/esp8266/lib/libnet80211_dbg.a | Bin 536888 -> 536888 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index 97aa97f42..8d717f964 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,6 +1,6 @@ gwen: core: cebfb0e - net80211: 074988c + net80211: eb73fdf pp: 5fda74f espnow: 7a93d71 diff --git a/components/esp8266/lib/libnet80211.a b/components/esp8266/lib/libnet80211.a index 1a72f88f0fe71ac08c8758f8f378fc9902c88757..1b6d53fd510d4165cfb6d6a31295871ab5651380 100755 GIT binary patch delta 566 zcmdmRMs~v)*$L9@hQ>yQ=H^Blm2R5B*pvO9h;5cIe=Y_Sm|pjsQGBzkpPejRfl-x#)2PB2y5f${TF3C`Phh^=x0oCmb#lMn!w C-L%U9 delta 566 zcmdmRMs~v)*$L9@1{Q{976z6Zm2R5B*pvO9h;5cIe=Y_Sm|pjsQGBzkpPejRfl-x#)2PB2y5f${TF3C`Phh^=x0oCmb#lMn#i CEVcpw diff --git a/components/esp8266/lib/libnet80211_dbg.a b/components/esp8266/lib/libnet80211_dbg.a index e432d685b7b93bc2532e91d9f118a3e4252af8a9..65fc6a233e42d360092355a8a378eb7210c5e53f 100755 GIT binary patch delta 568 zcmdn-NMXk#g$dH^hQ>yQ<`xDUm2R5B*wg=YGl_4OG=C-r6Pe66TWqt8U$`2Iz=V== zxWHz<*^RO&vTJr+mVyaPKlhPUeDmDP*A(C)dVN4UCVqJ|3oi0*J+t`siT#Xu#V{eD zwc^`lnVIyMVItc>PGg#$$-yLqEF{J>^#BW(KtV>OUcSDenGw`e(?OPOKgq>p#S2pn zcFA@{38p4RxDeRlgO*IwxM4!u<6M~{ZQ;CqO-yfDVLX_lWSFNv?M8KmCKF82cA(9P z-7wyCpmE~c*Ge+)V}}cYoz|(yysri(wB2tW^GrcF59q3=0WcoeCtE+VTxx)efI?#X z!$uarTW}$;nZ7ZsRa0R?+kpYEC&j2V{Vz9LJfl*3EDziESRQsJSC|4&%x2>-whb delta 568 zcmdn-NMXk#g$dH^1{Q{97KY{c0~!MCPlaq*y4khOw+hwLfhk9nIdiBynRhfZ&_hHn4@Hvr$6mRb%rJrRFV01 zpv{ThFy3^aapK$8N;2y-Q(;2efdQ{4#b`ABFE?8}qfvV-58L)w9(E>Im;zADZm$Vs a&sT+sOb0qcd^=}3yV-J7p;$SN+d=>t>ZlO_ From f7b047509db155768cd2d77e58557b8a980bc845 Mon Sep 17 00:00:00 2001 From: Zhang Jun Hao Date: Fri, 21 May 2021 15:18:46 +0800 Subject: [PATCH 15/57] fix(wifi): fragment and forge vulnerability detection --- components/wpa_supplicant/src/common/wpa_common.h | 2 ++ components/wpa_supplicant/src/rsn_supp/wpa_ie.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/components/wpa_supplicant/src/common/wpa_common.h b/components/wpa_supplicant/src/common/wpa_common.h index f88e8a6fa..fd1d9995a 100644 --- a/components/wpa_supplicant/src/common/wpa_common.h +++ b/components/wpa_supplicant/src/common/wpa_common.h @@ -110,6 +110,8 @@ #define WPA_CAPABILITY_MFPR BIT(6) #define WPA_CAPABILITY_MFPC BIT(7) #define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9) +#define WPA_CAPABILITY_SPP_CAPABLE BIT(10) +#define WPA_CAPABILITY_SPP_REQUIRED BIT(11) /* IEEE 802.11r */ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c index d648a4542..5ad24bb99 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c @@ -225,6 +225,9 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, } } #endif /* CONFIG_IEEE80211W */ + + capab |= WPA_CAPABILITY_SPP_CAPABLE; + WPA_PUT_LE16(pos, capab); pos += 2; From 8a2ab31b50fb891075cebb1bece0eb99678bad0a Mon Sep 17 00:00:00 2001 From: Zhang Jun Hao Date: Fri, 21 May 2021 15:23:19 +0800 Subject: [PATCH 16/57] fix(lib): update lib --- components/esp8266/lib/VERSION | 8 ++++---- components/esp8266/lib/libcore.a | Bin 39398 -> 39742 bytes components/esp8266/lib/libcore_dbg.a | Bin 40306 -> 40650 bytes components/esp8266/lib/libespnow.a | Bin 38660 -> 38660 bytes components/esp8266/lib/libespnow_dbg.a | Bin 38660 -> 38660 bytes components/esp8266/lib/libnet80211.a | Bin 484912 -> 485864 bytes components/esp8266/lib/libnet80211_dbg.a | Bin 536888 -> 537592 bytes components/esp8266/lib/libpp.a | Bin 247158 -> 249654 bytes components/esp8266/lib/libpp_dbg.a | Bin 264598 -> 267410 bytes 9 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index 8d717f964..6f12cd1ad 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,8 +1,8 @@ gwen: - core: cebfb0e - net80211: eb73fdf - pp: 5fda74f - espnow: 7a93d71 + core: 231e0e2 + net80211: 231e0e2 + pp: 231e0e2 + espnow: 231e0e2 smartconfig: 3.0.0/5f550c40 phy: 1163.0 diff --git a/components/esp8266/lib/libcore.a b/components/esp8266/lib/libcore.a index 75f2cd848a0f2f82db56e8b0dc0c4a5d37704af7..8beb25fae1a526487b1312062de4712ec4ad02ad 100755 GIT binary patch delta 11013 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 Kr)go51^)}^;-K#U diff --git a/components/esp8266/lib/libcore_dbg.a b/components/esp8266/lib/libcore_dbg.a index c59cd3276841122a73f6d7481fe215a4ecb5b2eb..45b00afe0339b849dc96a0e44addc88d216827f1 100755 GIT binary patch delta 11797 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 U@Guhnd7F}#hWZ(B=!gUV7r7xOVgLXD delta 11075 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 KHv5KccK`r({1PGn delta 68 zcmZo!$JDZpX@V4oftjU+nWcf*Mx_#FIA`-b<`P3VZ}L25vCRgiY>JGAlNG~+nGH=1 KH~WTdcK`r-RT41( diff --git a/components/esp8266/lib/libespnow_dbg.a b/components/esp8266/lib/libespnow_dbg.a index e3c2f9d3ce32e14b62e3deeb8705d37fc9d22478..2c7346c7b2ebafcbda4395a36e780b5abc29f8ae 100755 GIT binary patch delta 68 zcmZo!$JDZpX@V4ok)f%%rJ1SGMx_#FIA`-b<`P3VZ}L25vCRgiY>JE~lNG~+nGH=% KHv5KccK`r)1rj0v delta 68 zcmZo!$JDZpX@V4oftjU+nWeGeMx_#FIA`-b<`P3VZ}L25vCRgiY>JGAlNG~+nGH=1 KH~WTdcK`r+b`mQ9 diff --git a/components/esp8266/lib/libnet80211.a b/components/esp8266/lib/libnet80211.a index 1b6d53fd510d4165cfb6d6a31295871ab5651380..375abf9858481617da14acdfc5e6d7fc94215525 100755 GIT binary patch delta 48669 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 V8TU+LWD!5Cd68q9O*oV${U6kG!!Q5< delta 48182 zcmcG%3w#vS-9A1udr4q-!)6nbAOUtKcSs=F012015-@;r4G<6kN#v%20!A*@x(FIk zqXJ7k*n$SUR;hxZ3l%k>M%sb`#Y_8QMMR7BhKLGClK=C}o{=H7@B4q-_jf*-e4q22 z@A;nlnKQFzW={OM%a(mzR;7jtg9SxJLBBuWPiOt__ZJlQ$?t3M)7vYGdQwsPp7`G% zBfn6Te|d!do51UbDayZd)O!`>|IhK%7)1&3-_ISdl`6{rbR6%kDF5LR`tJ;=i&K^V z)$#WkifSHTdlmKPj`MRA^}-Rddj2KWy2dIO9XY!c?LRpxa}{lpA4iD)a7`TtD@LjQi%{jW0Md}O=wb4Tds z$e*}9k15W7^N1OjuKW+jwKHeV4A0EyD1P@Bd-}Gs>4oaHOVfU-ZX2ICLko}Y*j`N8 z=;#1D2PB({eUa4y;I-u6h>OEl5-ReQ3yWr^kuS0+Ce9+KMK2>;EE zc2D?#e`5GI1%D0iNa|&f_pY?J+txpDg&OXb?B1qj9#X@9PwKhthD+X6jqv(Q>^^a= z)0P+B*6AfO&!=3cZo471v$pN#;8ty0OwJp&Z6|W?wr^Y1{=;_LK8_8m+YVx-1{>%4#)Z}P$>IC@#DzEaZFfnp=sL+* z8u4F2-(W#>Atl~=%bubY2E+N2vQ=*+{%!kW)m@OEpErAEpT0#iuPG9{o3tU~)dqWP zUF8H)UF~SbyB^Rga6` z9k*wxYsEVhy+t#G#~r6Ac1=-o6h+AtyZdXM9mRG<*(%hXTAJsJ7)9BF(C!FL74ZWQ zx*qGo+r`GW?1`NUihrt(HdWGcmowScyH8)EPEJO4ZnZaS7u88*_jdcGF_Gq%?8$M+ zYsWt#=e1%c#X9i<#V+Ca6GXO{Kruo*PBCA6N3m91whv;5_!Y$w@d?F1(Pw|O;QQ@q zj-X9Zio>^$O%Ut%qwLp--|a`C8^t>mdqgvYXGnsgY)0vFQM#OH*>7+v%7@Xik3m86 zVI>ctU5&D<%fyDa(E0s?wRZ76Z|v2k(9;HJNs+zpsYmS>74@g)_l7Tx#6~)Npzg4X zDL2@4@oaC+C;abfagp}NRIQ^rF#OG;1mXWd^{OXC!4GPd!|yOlG5-g(*f9y--lF

muREKOYdldMGN!j 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

$UH6OUsXS(+pxX-@s_~jom;$# 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 OhvD8Cjx#Fi@BagFn9eW& literal 158922 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 CD)~_W From c8a91e0aa3b1979faef5276a78a514a391288f54 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Mon, 26 Jul 2021 11:59:35 +0800 Subject: [PATCH 18/57] chore(ci): Modify SSC branch for CI --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 83b515304..f884330ee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,7 +48,7 @@ build_ssc: - git clone $GITLAB_SSH_SERVER/yinling/SSC.git - cd SSC # try checkout same branch - - git checkout "${CI_BUILD_REF_NAME}_8266" || echo "Using default branch..." + - git checkout "release/v3.4_8266" || echo "Using default branch..." - ./gen_misc_rtos.sh push_master_to_github: From f09d86123d2d8621e270584d84e422122dcfb5ca Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 23 Jul 2021 17:05:40 +0800 Subject: [PATCH 19/57] feat(nvs_flash): Bring nvs_flash from esp-idf Commit ID: ecd2c51 --- components/nvs_flash/CMakeLists.txt | 53 +- components/nvs_flash/Kconfig | 12 + components/nvs_flash/README.rst | 234 -- components/nvs_flash/component.mk | 4 +- .../host_test/fixtures/test_fixtures.hpp | 429 +++ .../host_test/nvs_page_test/CMakeLists.txt | 27 + .../host_test/nvs_page_test/README.rst | 23 + .../nvs_page_test/main/CMakeLists.txt | 10 + .../nvs_page_test/main/nvs_page_test.cpp | 934 ++++++ .../nvs_page_test/sdkconfig.defaults | 3 + components/nvs_flash/include/nvs.h | 488 ++- components/nvs_flash/include/nvs_flash.h | 158 +- components/nvs_flash/include/nvs_handle.hpp | 280 ++ .../{test_nvs_host => mock/int}/crc.cpp | 5 +- .../{test_nvs_host => mock/int}/crc.h | 6 +- .../nvs_partition_generator/README.rst | 308 +- .../nvs_partition_generator/README_CN.rst | 304 ++ .../nvs_partition_gen.py | 823 +++-- .../sample_multipage_blob.csv | 1 + .../sample_singlepage_blob.csv | 1 + .../nvs_flash/src/compressed_enum_table.hpp | 4 +- components/nvs_flash/src/intrusive_list.h | 14 +- components/nvs_flash/src/nvs_api.cpp | 670 ++-- components/nvs_flash/src/nvs_cxx_api.cpp | 68 + .../nvs_flash/src/nvs_encrypted_partition.cpp | 121 + .../nvs_flash/src/nvs_encrypted_partition.hpp | 43 + .../nvs_flash/src/nvs_handle_locked.cpp | 82 + .../nvs_flash/src/nvs_handle_locked.hpp | 66 + .../nvs_flash/src/nvs_handle_simple.cpp | 137 + .../nvs_flash/src/nvs_handle_simple.hpp | 107 + .../nvs_flash/src/nvs_item_hash_list.cpp | 28 +- .../nvs_flash/src/nvs_item_hash_list.hpp | 8 +- components/nvs_flash/src/nvs_page.cpp | 319 +- components/nvs_flash/src/nvs_page.hpp | 52 +- components/nvs_flash/src/nvs_pagemanager.cpp | 53 +- components/nvs_flash/src/nvs_pagemanager.hpp | 15 +- components/nvs_flash/src/nvs_partition.cpp | 77 + components/nvs_flash/src/nvs_partition.hpp | 115 + .../nvs_flash/src/nvs_partition_lookup.cpp | 69 + .../nvs_flash/src/nvs_partition_lookup.hpp | 22 + .../nvs_flash/src/nvs_partition_manager.cpp | 244 ++ .../nvs_flash/src/nvs_partition_manager.hpp | 62 + components/nvs_flash/src/nvs_platform.hpp | 35 +- components/nvs_flash/src/nvs_storage.cpp | 576 +++- components/nvs_flash/src/nvs_storage.hpp | 75 +- components/nvs_flash/src/nvs_test_api.h | 22 +- components/nvs_flash/src/nvs_types.cpp | 19 +- components/nvs_flash/src/nvs_types.hpp | 64 +- components/nvs_flash/src/partition.hpp | 59 + components/nvs_flash/test/CMakeLists.txt | 4 + components/nvs_flash/test/component.mk | 1 + components/nvs_flash/test/encryption_keys.bin | 1 + .../nvs_flash/test/partition_encrypted.bin | Bin 0 -> 8192 bytes components/nvs_flash/test/sample.bin | 1 + components/nvs_flash/test/test_nvs.c | 495 ++- components/nvs_flash/test_nvs_host/Makefile | 63 +- components/nvs_flash/test_nvs_host/README.md | 22 + .../test_nvs_host/esp_error_check_stub.cpp | 7 +- .../nvs_flash/test_nvs_host/sdkconfig.h | 3 + .../test_nvs_host/spi_flash_emulation.cpp | 61 +- .../test_nvs_host/spi_flash_emulation.h | 36 +- .../test_compressed_enum_table.cpp | 2 +- .../nvs_flash/test_nvs_host/test_fixtures.hpp | 149 + .../test_nvs_host/test_intrusive_list.cpp | 7 +- .../nvs_flash/test_nvs_host/test_nvs.cpp | 2777 +++++++++++++++-- .../test_nvs_host/test_nvs_cxx_api.cpp | 193 ++ .../test_nvs_host/test_nvs_handle.cpp | 281 ++ .../test_nvs_host/test_nvs_initialization.cpp | 46 + .../test_nvs_host/test_nvs_partition.cpp | 55 + .../test_nvs_host/test_nvs_storage.cpp | 60 + .../test_nvs_host/test_partition_manager.cpp | 91 + .../test_spi_flash_emulation.cpp | 189 +- 72 files changed, 10427 insertions(+), 1446 deletions(-) create mode 100644 components/nvs_flash/Kconfig delete mode 100644 components/nvs_flash/README.rst create mode 100644 components/nvs_flash/host_test/fixtures/test_fixtures.hpp create mode 100644 components/nvs_flash/host_test/nvs_page_test/CMakeLists.txt create mode 100644 components/nvs_flash/host_test/nvs_page_test/README.rst create mode 100644 components/nvs_flash/host_test/nvs_page_test/main/CMakeLists.txt create mode 100644 components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp create mode 100644 components/nvs_flash/host_test/nvs_page_test/sdkconfig.defaults create mode 100644 components/nvs_flash/include/nvs_handle.hpp rename components/nvs_flash/{test_nvs_host => mock/int}/crc.cpp (97%) rename components/nvs_flash/{test_nvs_host => mock/int}/crc.h (72%) create mode 100644 components/nvs_flash/nvs_partition_generator/README_CN.rst create mode 100644 components/nvs_flash/src/nvs_cxx_api.cpp create mode 100644 components/nvs_flash/src/nvs_encrypted_partition.cpp create mode 100644 components/nvs_flash/src/nvs_encrypted_partition.hpp create mode 100644 components/nvs_flash/src/nvs_handle_locked.cpp create mode 100644 components/nvs_flash/src/nvs_handle_locked.hpp create mode 100644 components/nvs_flash/src/nvs_handle_simple.cpp create mode 100644 components/nvs_flash/src/nvs_handle_simple.hpp create mode 100644 components/nvs_flash/src/nvs_partition.cpp create mode 100644 components/nvs_flash/src/nvs_partition.hpp create mode 100644 components/nvs_flash/src/nvs_partition_lookup.cpp create mode 100644 components/nvs_flash/src/nvs_partition_lookup.hpp create mode 100644 components/nvs_flash/src/nvs_partition_manager.cpp create mode 100644 components/nvs_flash/src/nvs_partition_manager.hpp create mode 100644 components/nvs_flash/src/partition.hpp create mode 100644 components/nvs_flash/test/CMakeLists.txt create mode 100644 components/nvs_flash/test/encryption_keys.bin create mode 100644 components/nvs_flash/test/partition_encrypted.bin create mode 100644 components/nvs_flash/test/sample.bin create mode 100644 components/nvs_flash/test_nvs_host/README.md create mode 100644 components/nvs_flash/test_nvs_host/test_fixtures.hpp create mode 100644 components/nvs_flash/test_nvs_host/test_nvs_cxx_api.cpp create mode 100644 components/nvs_flash/test_nvs_host/test_nvs_handle.cpp create mode 100644 components/nvs_flash/test_nvs_host/test_nvs_initialization.cpp create mode 100644 components/nvs_flash/test_nvs_host/test_nvs_partition.cpp create mode 100644 components/nvs_flash/test_nvs_host/test_nvs_storage.cpp create mode 100644 components/nvs_flash/test_nvs_host/test_partition_manager.cpp diff --git a/components/nvs_flash/CMakeLists.txt b/components/nvs_flash/CMakeLists.txt index b36e6ba52..7ce2871c1 100644 --- a/components/nvs_flash/CMakeLists.txt +++ b/components/nvs_flash/CMakeLists.txt @@ -1,6 +1,51 @@ -set(COMPONENT_SRCDIRS "src") -set(COMPONENT_ADD_INCLUDEDIRS "include") +idf_build_get_property(target IDF_TARGET) -set(COMPONENT_PRIV_REQUIRES "spi_flash") +set(srcs "src/nvs_api.cpp" + "src/nvs_cxx_api.cpp" + "src/nvs_item_hash_list.cpp" + "src/nvs_page.cpp" + "src/nvs_pagemanager.cpp" + "src/nvs_storage.cpp" + "src/nvs_handle_simple.cpp" + "src/nvs_handle_locked.cpp" + "src/nvs_partition.cpp" + "src/nvs_partition_lookup.cpp" + "src/nvs_partition_manager.cpp" + "src/nvs_types.cpp") -register_component() +set(public_req spi_flash) + +set(include_dirs "include") + +idf_component_register(SRCS "${srcs}" + REQUIRES "${public_req}" + INCLUDE_DIRS "${include_dirs}") + +# If we use the linux target, we need to redirect the crc functions to the linux +if(${target} STREQUAL "linux") + if(CONFIG_NVS_ENCRYPTION) + # mbedtls isn't configured for building with linux or as mock target. It will draw in all kind of dependencies + message(FATAL_ERROR "NVS currently doesn't support encryption if built for Linux.") + endif() + idf_component_get_property(spi_flash_dir spi_flash COMPONENT_DIR) + target_include_directories(${COMPONENT_LIB} PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/mock/int" + "${spi_flash_dir}/sim/stubs/freertos/include") + target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/mock/int/crc.cpp") + target_compile_options(${COMPONENT_LIB} PUBLIC "-DLINUX_TARGET") +else() + # TODO: this is a workaround until IDF-2085 is fixed + idf_component_get_property(mbedtls_lib mbedtls COMPONENT_LIB) + target_link_libraries(${COMPONENT_LIB} PUBLIC ${mbedtls_lib}) +endif() + +if(CONFIG_NVS_ENCRYPTION) + target_sources(${COMPONENT_LIB} PRIVATE "src/nvs_encrypted_partition.cpp") + idf_component_get_property(mbedtls_lib mbedtls COMPONENT_LIB) + target_link_libraries(${COMPONENT_LIB} PUBLIC ${mbedtls_lib}) +endif() + +if(${target} STREQUAL "linux") + target_compile_options(${COMPONENT_LIB} PUBLIC --coverage) + target_link_libraries(${COMPONENT_LIB} PUBLIC --coverage) +endif() diff --git a/components/nvs_flash/Kconfig b/components/nvs_flash/Kconfig new file mode 100644 index 000000000..98cf97987 --- /dev/null +++ b/components/nvs_flash/Kconfig @@ -0,0 +1,12 @@ +menu "NVS" + + config NVS_ENCRYPTION + bool "Enable NVS encryption" + default y + depends on SECURE_FLASH_ENC_ENABLED + help + This option enables encryption for NVS. When enabled, AES-XTS is used to encrypt + the complete NVS data, except the page headers. It requires XTS encryption keys + to be stored in an encrypted partition. This means enabling flash encryption is + a pre-requisite for this feature. +endmenu diff --git a/components/nvs_flash/README.rst b/components/nvs_flash/README.rst deleted file mode 100644 index f04ac592c..000000000 --- a/components/nvs_flash/README.rst +++ /dev/null @@ -1,234 +0,0 @@ -Non-volatile storage library -============================ - -Introduction ------------- - -Non-volatile storage (NVS) library is designed to store key-value pairs in flash. This sections introduces some concepts used by NVS. - -Underlying storage -^^^^^^^^^^^^^^^^^^ - -Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The library uses the all the partitions with ``data`` type and ``nvs`` subtype. The application can choose to use the partition with label ``nvs`` through ``nvs_open`` API or any of the other partition by specifying its name through ``nvs_open_from_part`` API. - -Future versions of this library may add other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. - -.. note:: if an NVS partition is truncated (for example, when the partition table layout is changed), its contents should be erased. ESP-IDF build system provides a ``make erase_flash`` target to erase all contents of the flash chip. - -.. note:: NVS works best for storing many small values, rather than a few large values of type 'string' and 'blob'. If storing large blobs or strings is required, consider using the facilities provided by the FAT filesystem on top of the wear levelling library. - -Keys and values -^^^^^^^^^^^^^^^ - -NVS operates on key-value pairs. Keys are ASCII strings, maximum key length is currently 15 characters. Values can have one of the following types: - -- integer types: ``uint8_t``, ``int8_t``, ``uint16_t``, ``int16_t``, ``uint32_t``, ``int32_t``, ``uint64_t``, ``int64_t`` -- zero-terminated string -- variable length binary data (blob) - -.. note:: - String and blob values are currently limited to 1984 bytes. For strings, this includes the null terminator. - -Additional types, such as ``float`` and ``double`` may be added later. - -Keys are required to be unique. Writing a value for a key which already exists behaves as follows: - -- if the new value is of the same type as old one, value is updated -- if the new value has different data type, an error is returned - -Data type check is also performed when reading a value. An error is returned if data type of read operation doesn’t match the data type of the value. - -Namespaces -^^^^^^^^^^ - -To mitigate potential conflicts in key names between different components, NVS assigns each key-value pair to one of namespaces. Namespace names follow the same rules as key names, i.e. 15 character maximum length. Namespace name is specified in the ``nvs_open`` or ``nvs_open_from_part`` call. This call returns an opaque handle, which is used in subsequent calls to ``nvs_read_*``, ``nvs_write_*``, and ``nvs_commit`` functions. This way, handle is associated with a namespace, and key names will not collide with same names in other namespaces. -Please note that the namespaces with same name in different NVS partitions are considered as separate namespaces. - -Security, tampering, and robustness -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -NVS library doesn't implement tamper prevention measures. It is possible for anyone with physical access to the flash chip to alter, erase, or add key-value pairs. - -NVS is compatible with the ESP32 flash encryption system, and it can store key-value pairs in an encrypted form. Some metadata, like page state and write/erase flags of individual entries can not be encrypted as they are represented as bits of flash memory for efficient access and manipulation. Flash encryption can prevent some forms of modification: - -- replacing keys or values with arbitrary data -- changing data types of values - -The following forms of modification are still possible when flash encryption is used: - -- erasing a page completely, removing all key-value pairs which were stored in that page -- corrupting data in a page, which will cause the page to be erased automatically when such condition is detected -- rolling back the contents of flash memory to an earlier snapshot -- merging two snapshots of flash memory, rolling back some key-value pairs to an earlier state (although this is possible to mitigate with the current design — TODO) - -The library does try to recover from conditions when flash memory is in an inconsistent state. In particular, one should be able to power off the device at any point and time and then power it back on. This should not result in loss of data, expect for the new key-value pair if it was being written at the moment of power off. The library should also be able to initialize properly with any random data present in flash memory. - -Internals ---------- - -Log of key-value pairs -^^^^^^^^^^^^^^^^^^^^^^ - -NVS stores key-value pairs sequentially, with new key-value pairs being added at the end. When a value of any given key has to be updated, new key-value pair is added at the end of the log and old key-value pair is marked as erased. - -Pages and entries -^^^^^^^^^^^^^^^^^ - -NVS library uses two main entities in its operation: pages and entries. Page is a logical structure which stores a portion of the overall log. Logical page corresponds to one physical sector of flash memory. Pages which are in use have a *sequence number* associated with them. Sequence numbers impose an ordering on pages. Higher sequence numbers correspond to pages which were created later. Each page can be in one of the following states: - -Empty/uninitialized - Flash storage for the page is empty (all bytes are ``0xff``). Page isn't used to store any data at this point and doesn’t have a sequence number. - -Active - Flash storage is initialized, page header has been written to flash, page has a valid sequence number. Page has some empty entries and data can be written there. At most one page can be in this state at any given moment. - -Full - Flash storage is in a consistent state and is filled with key-value pairs. - Writing new key-value pairs into this page is not possible. It is still possible to mark some key-value pairs as erased. - -Erasing - Non-erased key-value pairs are being moved into another page so that the current page can be erased. This is a transient state, i.e. page should never stay in this state when any API call returns. In case of a sudden power off, move-and-erase process will be completed upon next power on. - -Corrupted - Page header contains invalid data, and further parsing of page data was canceled. Any items previously written into this page will not be accessible. Corresponding flash sector will not be erased immediately, and will be kept along with sectors in *uninitialized* state for later use. This may be useful for debugging. - -Mapping from flash sectors to logical pages doesn't have any particular order. Library will inspect sequence numbers of pages found in each flash sector and organize pages in a list based on these numbers. - -:: - - +--------+ +--------+ +--------+ +--------+ - | Page 1 | | Page 2 | | Page 3 | | Page 4 | - | Full +---> | Full +---> | Active | | Empty | <- states - | #11 | | #12 | | #14 | | | <- sequence numbers - +---+----+ +----+---+ +----+---+ +---+----+ - | | | | - | | | | - | | | | - +---v------+ +-----v----+ +------v---+ +------v---+ - | Sector 3 | | Sector 0 | | Sector 2 | | Sector 1 | <- physical sectors - +----------+ +----------+ +----------+ +----------+ - -Structure of a page -^^^^^^^^^^^^^^^^^^^ - -For now we assume that flash sector size is 4096 bytes and that ESP32 flash encryption hardware operates on 32-byte blocks. It is possible to introduce some settings configurable at compile-time (e.g. via menuconfig) to accommodate flash chips with different sector sizes (although it is not clear if other components in the system, e.g. SPI flash driver and SPI flash cache can support these other sizes). - -Page consists of three parts: header, entry state bitmap, and entries themselves. To be compatible with ESP32 flash encryption, entry size is 32 bytes. For integer types, entry holds one key-value pair. For strings and blobs, an entry holds part of key-value pair (more on that in the entry structure description). - -The following diagram illustrates page structure. Numbers in parentheses indicate size of each part in bytes. :: - - +-----------+--------------+-------------+-----------+ - | State (4) | Seq. no. (4) | Unused (20) | CRC32 (4) | Header (32) - +-----------+--------------+-------------+-----------+ - | Entry state bitmap (32) | - +----------------------------------------------------+ - | Entry 0 (32) | - +----------------------------------------------------+ - | Entry 1 (32) | - +----------------------------------------------------+ - / / - / / - +----------------------------------------------------+ - | Entry 125 (32) | - +----------------------------------------------------+ - -Page header and entry state bitmap are always written to flash unencrypted. Entries are encrypted if flash encryption feature of the ESP32 is used. - -Page state values are defined in such a way that changing state is possible by writing 0 into some of the bits. Therefore it not necessary to erase the page to change page state, unless that is a change to *erased* state. - -CRC32 value in header is calculated over the part which doesn't include state value (bytes 4 to 28). Unused part is currently filled with ``0xff`` bytes. Future versions of the library may store format version there. - -The following sections describe structure of entry state bitmap and entry itself. - -Entry and entry state bitmap -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Each entry can be in one of the following three states. Each state is represented with two bits in the entry state bitmap. Final four bits in the bitmap (256 - 2 * 126) are unused. - -Empty (2'b11) - Nothing is written into the specific entry yet. It is in an uninitialized state (all bytes ``0xff``). - -Written (2'b10) - A key-value pair (or part of key-value pair which spans multiple entries) has been written into the entry. - -Erased (2'b00) - A key-value pair in this entry has been discarded. Contents of this entry will not be parsed anymore. - - -Structure of entry -^^^^^^^^^^^^^^^^^^ - -For values of primitive types (currently integers from 1 to 8 bytes long), entry holds one key-value pair. For string and blob types, entry holds part of the whole key-value pair. In case when a key-value pair spans multiple entries, all entries are stored in the same page. - -:: - - +--------+----------+----------+---------+-----------+---------------+----------+ - | NS (1) | Type (1) | Span (1) | Rsv (1) | CRC32 (4) | Key (16) | Data (8) | - +--------+----------+----------+---------+-----------+---------------+----------+ - - +--------------------------------+ - +-> Fixed length: | Data (8) | - | +--------------------------------+ - Data format ---+ - | +----------+---------+-----------+ - +-> Variable length: | Size (2) | Rsv (2) | CRC32 (4) | - +----------+---------+-----------+ - - -Individual fields in entry structure have the following meanings: - -NS - Namespace index for this entry. See section on namespaces implementation for explanation of this value. - -Type - One byte indicating data type of value. See ``ItemType`` enumeration in ``nvs_types.h`` for possible values. - -Span - Number of entries used by this key-value pair. For integer types, this is equal to 1. For strings and blobs this depends on value length. - -Rsv - Unused field, should be ``0xff``. - -CRC32 - Checksum calculated over all the bytes in this entry, except for the CRC32 field itself. - -Key - Zero-terminated ASCII string containing key name. Maximum string length is 15 bytes, excluding zero terminator. - -Data - For integer types, this field contains the value itself. If the value itself is shorter than 8 bytes it is padded to the right, with unused bytes filled with ``0xff``. For string and blob values, these 8 bytes hold additional data about the value, described next: - -Size - (Only for strings and blobs.) Size, in bytes, of actual data. For strings, this includes zero terminator. - -CRC32 - (Only for strings and blobs.) Checksum calculated over all bytes of data. - -Variable length values (strings and blobs) are written into subsequent entries, 32 bytes per entry. `Span` field of the first entry indicates how many entries are used. - - -Namespaces -^^^^^^^^^^ - -As mentioned above, each key-value pair belongs to one of the namespaces. Namespaces identifiers (strings) are stored as keys of key-value pairs in namespace with index 0. Values corresponding to these keys are indexes of these namespaces. - -:: - - +-------------------------------------------+ - | NS=0 Type=uint8_t Key="wifi" Value=1 | Entry describing namespace "wifi" - +-------------------------------------------+ - | NS=1 Type=uint32_t Key="channel" Value=6 | Key "channel" in namespace "wifi" - +-------------------------------------------+ - | NS=0 Type=uint8_t Key="pwm" Value=2 | Entry describing namespace "pwm" - +-------------------------------------------+ - | NS=2 Type=uint16_t Key="channel" Value=20 | Key "channel" in namespace "pwm" - +-------------------------------------------+ - - -Item hash list -^^^^^^^^^^^^^^ - -To reduce the number of reads performed from flash memory, each member of Page class maintains a list of pairs: (item index; item hash). This list makes searches much quicker. Instead of iterating over all entries, reading them from flash one at a time, ``Page::findItem`` first performs search for item hash in the hash list. This gives the item index within the page, if such an item exists. Due to a hash collision it is possible that a different item will be found. This is handled by falling back to iteration over items in flash. - -Each node in hash list contains a 24-bit hash and 8-bit item index. Hash is calculated based on item namespace and key name. CRC32 is used for calculation, result is truncated to 24 bits. To reduce overhead of storing 32-bit entries in a linked list, list is implemented as a doubly-linked list of arrays. Each array holds 29 entries, for the total size of 128 bytes, together with linked list pointers and 32-bit count field. Minimal amount of extra RAM useage per page is therefore 128 bytes, maximum is 640 bytes. - diff --git a/components/nvs_flash/component.mk b/components/nvs_flash/component.mk index 20b0ec407..8b2fda4f5 100755 --- a/components/nvs_flash/component.mk +++ b/components/nvs_flash/component.mk @@ -6,4 +6,6 @@ COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_SRCDIRS := src -CPPFLAGS += -DNVS_CRC_HEADER_FILE=\"rom/crc.h\" +ifndef CONFIG_NVS_ENCRYPTION +COMPONENT_OBJEXCLUDE := src/nvs_encr.o +endif diff --git a/components/nvs_flash/host_test/fixtures/test_fixtures.hpp b/components/nvs_flash/host_test/fixtures/test_fixtures.hpp new file mode 100644 index 000000000..06b12ce17 --- /dev/null +++ b/components/nvs_flash/host_test/fixtures/test_fixtures.hpp @@ -0,0 +1,429 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "nvs_partition.hpp" +#include "nvs.h" +#include "nvs_page.hpp" +#include "nvs_storage.hpp" +#include +#include + +#ifdef CONFIG_NVS_ENCRYPTION +#include "nvs_encrypted_partition.hpp" +#endif + +extern "C" { +#include "Mockesp_partition.h" +} + +struct FixtureException : std::exception { + FixtureException(const std::string& msg) : msg(msg) { } + + const char *what() { + return msg.c_str(); + } + + std::string msg; +}; + +class PartitionMock : public nvs::Partition { +public: + PartitionMock(uint32_t address, uint32_t size) + : partition(), address(address), size(size) + { + assert(size); + } + + const char *get_partition_name() override + { + return ""; + } + + esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override + { + return esp_partition_read_raw(&partition, src_offset, dst, size); + } + + esp_err_t read(size_t src_offset, void* dst, size_t size) override + { + return esp_partition_read(&partition, src_offset, dst, size); + } + + esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override + { + return esp_partition_write_raw(&partition, dst_offset, src, size); + } + + esp_err_t write(size_t dst_offset, const void* src, size_t size) override + { + return esp_partition_write(&partition, dst_offset, src, size); + } + + esp_err_t erase_range(size_t dst_offset, size_t size) override + { + return esp_partition_erase_range(&partition, dst_offset, size); + } + + uint32_t get_address() override + { + return address; + } + + uint32_t get_size() override + { + return size; + } + + const esp_partition_t partition; + +private: + uint32_t address; + + uint32_t size; +}; + +#ifdef CONFIG_NVS_ENCRYPTION +struct EncryptedPartitionFixture { + EncryptedPartitionFixture(nvs_sec_cfg_t *cfg, + uint32_t start_sector = 0, + uint32_t sector_size = 1, + const char *partition_name = NVS_DEFAULT_PART_NAME) + : esp_partition(), emu(start_sector + sector_size), + part(partition_name, &esp_partition) { + esp_partition.address = start_sector * SPI_FLASH_SEC_SIZE; + esp_partition.size = sector_size * SPI_FLASH_SEC_SIZE; + assert(part.init(cfg) == ESP_OK); + } + + ~EncryptedPartitionFixture() { } + + esp_partition_t esp_partition; + + SpiFlashEmulator emu; + + nvs::NVSEncryptedPartition part; +}; +#endif + +struct PartitionMockFixture { + PartitionMockFixture(uint32_t start_sector = 0, + uint32_t sector_size = 1, + const char *partition_name = NVS_DEFAULT_PART_NAME) + : part_mock(start_sector * SPI_FLASH_SEC_SIZE, sector_size * SPI_FLASH_SEC_SIZE) { + std::fill_n(raw_header, sizeof(raw_header)/sizeof(raw_header[0]), UINT8_MAX); + } + + ~PartitionMockFixture() { } + + uint8_t raw_header[512]; + + PartitionMock part_mock; +}; + +struct NVSPageFixture : public PartitionMockFixture { + NVSPageFixture(uint32_t start_sector = 0, + uint32_t sector_size = 1, + const char *partition_name = NVS_DEFAULT_PART_NAME) + : PartitionMockFixture(start_sector, sector_size, partition_name), page() + { + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 32); + + for (int i = 0; i < 8; i++) { + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512); + } + + if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page"); + } + + nvs::Page page; +}; + +struct NVSValidPageFixture : public PartitionMockFixture { + const static uint8_t NS_INDEX = 1; + + // valid header + uint8_t raw_header_valid [32]; + + // entry table with one entry + uint8_t raw_entry_table [32]; + + uint8_t ns_entry [32]; + + uint8_t value_entry [32]; + + NVSValidPageFixture(uint32_t start_sector = 0, + uint32_t sector_size = 1, + const char *partition_name = NVS_DEFAULT_PART_NAME) + : PartitionMockFixture(start_sector, sector_size, partition_name), + raw_header_valid {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc}, + ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + value_entry {0x01, 0x01, 0x01, 0xff, 0x3d, 0xf3, 0x99, 0xe5, 't', 'e', 's', 't', '_', 'v', 'a', 'l', + 'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + page() + { + std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0); + raw_entry_table[0] = 0xfa; + + // read page header + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32); + + // read entry table + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32); + + // read next free entry's header + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 4); + + // read namespace entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32); + + // read normal entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32); + + // read normal entry second time during duplicated entry check + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32); + + if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page"); + } + + nvs::Page page; +}; + +struct NVSValidStorageFixture : public PartitionMockFixture { + const static uint8_t NS_INDEX = 1; + + uint8_t ns_entry [32]; + + uint8_t empty_entry [32]; + + NVSValidStorageFixture(uint32_t start_sector = 0, + uint32_t sector_size = 3, + const char *partition_name = NVS_DEFAULT_PART_NAME) + : PartitionMockFixture(start_sector, sector_size, partition_name), + ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + empty_entry(), + storage(&part_mock) + { + std::fill_n(empty_entry, sizeof(empty_entry)/sizeof(empty_entry[0]), 0xFF); + + // entry table with one entry + uint8_t raw_entry_table [32]; + + uint8_t header_full_page [] = { + 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc}; + + uint8_t header_second_page [] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + uint8_t header_third_page [] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + // entry_table with all elements deleted except the namespace entry written and the last entry free + std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0); + raw_entry_table[0] = 0x02; + raw_entry_table[31] = 0xFC; + + // read full page header + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(header_full_page, 32); + + // read entry table + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32); + + // reading entry table checks empty entry + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(empty_entry, 32); + + // read namespace entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32); + + // read last two pages' headers, which trigger an automatic full read each because each page is empty + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(header_second_page, 32); + for (int i = 0; i < 8; i++) { + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512); + } + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(header_third_page, 32); + for (int i = 0; i < 8; i++) { + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512); + } + + // read namespace entry in duplicated header item check of pagemanager::load + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32); + + // storage finally actually reads namespace + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32); + + // storage looks for blob index entries + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32); + + // Storage::eraseOrphanDataBlobs() also wants to take it's turn... + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32); + + if (storage.init(start_sector, sector_size) != ESP_OK) throw FixtureException("couldn't setup page"); + } + + nvs::Storage storage; +}; + +struct NVSValidBlobPageFixture : public PartitionMockFixture { + const static uint8_t NS_INDEX = 1; + const static size_t BLOB_DATA_SIZE = 32; + + // valid header + uint8_t raw_header_valid [32]; + + // entry table with one entry + uint8_t raw_entry_table [32]; + + uint8_t ns_entry [32]; + + uint8_t blob_entry [32]; + uint8_t blob_data [BLOB_DATA_SIZE]; + uint8_t blob_index [32]; + + NVSValidBlobPageFixture(uint32_t start_sector = 0, + uint32_t sector_size = 1, + const char *partition_name = NVS_DEFAULT_PART_NAME) + : PartitionMockFixture(start_sector, sector_size, partition_name), + raw_header_valid {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc}, + ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + blob_entry {0x01, 0x42, 0x02, 0x00, 0xaa, 0xf3, 0x23, 0x87, 't', 'e', 's', 't', '_', 'b', 'l', 'o', + 'b', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 0x20, 0x00, 0xff, 0xff, 0xc6, 0x96, 0x86, 0xd9}, + blob_data {0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}, + blob_index {0x01, 0x48, 0x01, 0xff, 0x42, 0x6b, 0xdf, 0x66, 't', 'e', 's', 't', '_', 'b', 'l', 'o', + 'b', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff}, + page() + { + std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0xFF); + raw_entry_table[0] = 0xaa; + + // read page header + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32); + + // read entry table + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32); + + // read next free entry's header + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 4); + + // read namespace entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32); + + // read normal blob entry + index, not the data + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(blob_entry, 32); + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(blob_index, 32); + + // read normal entry second time during duplicated entry check + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(blob_entry, 32); + + if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page"); + } + + nvs::Page page; +}; + +struct NVSFullPageFixture : public PartitionMockFixture { + const static uint8_t NS_INDEX = 1; + + // valid header + uint8_t raw_header_valid [32]; + + // entry table with one entry + uint8_t raw_entry_table [32]; + + uint8_t ns_entry [32]; + + uint8_t value_entry [32]; + + NVSFullPageFixture(uint32_t start_sector = 0, + uint32_t sector_size = 1, + const char *partition_name = NVS_DEFAULT_PART_NAME, + bool load = true) + : PartitionMockFixture(start_sector, sector_size, partition_name), + raw_header_valid {0xfc, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x48, 0x9f, 0x38}, + ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + value_entry {0x01, 0x01, 0x01, 0xff, 0x3d, 0xf3, 0x99, 0xe5, 't', 'e', 's', 't', '_', 'v', 'a', 'l', + 'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + page() + { + std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0); + raw_entry_table[0] = 0xfa; + + // entry_table with all elements deleted except the namespace entry written and the last entry free + std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0); + raw_entry_table[0] = 0x0a; + raw_entry_table[31] = 0xFC; + + // read page header + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32); + + // read entry table + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32); + + // no next free entry check, only one entry written + + // read namespace entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32); + + // read normal entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32); + + // no duplicated entry check + + if (load) { + if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page"); + } + } + + nvs::Page page; +}; diff --git a/components/nvs_flash/host_test/nvs_page_test/CMakeLists.txt b/components/nvs_flash/host_test/nvs_page_test/CMakeLists.txt new file mode 100644 index 000000000..cafc7c699 --- /dev/null +++ b/components/nvs_flash/host_test/nvs_page_test/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(COMPONENTS main) +idf_build_set_property(CONFIG_SPI_FLASH_MOCK 1) +idf_build_set_property(COMPILE_DEFINITIONS "-DNO_DEBUG_STORAGE" APPEND) +project(host_nvs_page_test) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/build/coverage.info" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build" + COMMAND lcov --capture --directory . --output-file coverage.info + COMMENT "Create coverage report" + ) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/build/coverage_report/" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/build/coverage.info" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build" + COMMAND genhtml coverage.info --output-directory coverage_report/ + COMMENT "Turn coverage report into html-based visualization" + ) + +add_custom_target(coverage + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build" + DEPENDS "coverage_report/" + ) diff --git a/components/nvs_flash/host_test/nvs_page_test/README.rst b/components/nvs_flash/host_test/nvs_page_test/README.rst new file mode 100644 index 000000000..c005b3f48 --- /dev/null +++ b/components/nvs_flash/host_test/nvs_page_test/README.rst @@ -0,0 +1,23 @@ +NVS Page Test for Host +====================== + +Build +----- + +First, make sure that the target is set to linux. +Run ``idf.py --preview set-target linux`` to be sure. +Then do a normal IDF build: ``idf.py build``. + +Run +--- + +IDF monitor doesn't work yet for Linux. +You have to run the app manually: ``./build/host_nvs_page_test.elf``. + +Coverage +--- + +To generate the coverage, run: ``idf.py coverage``. +Afterwards, you can view the coverage by opening ``build/coverage_report/index.html`` with your browser. +Note that you need to run the application at least once before generating the coverage information. +If you run it multiple times, the coverage information adds up. diff --git a/components/nvs_flash/host_test/nvs_page_test/main/CMakeLists.txt b/components/nvs_flash/host_test/nvs_page_test/main/CMakeLists.txt new file mode 100644 index 000000000..d2af1b6a6 --- /dev/null +++ b/components/nvs_flash/host_test/nvs_page_test/main/CMakeLists.txt @@ -0,0 +1,10 @@ +idf_component_register(SRCS "nvs_page_test.cpp" + INCLUDE_DIRS + "." + "${CMAKE_CURRENT_SOURCE_DIR}/../../fixtures" + "${CMAKE_CURRENT_SOURCE_DIR}/../../../test_nvs_host" + "${CMAKE_CURRENT_SOURCE_DIR}/../../../src" + REQUIRES cmock nvs_flash spi_flash) + +target_compile_options(${COMPONENT_LIB} PUBLIC --coverage) +target_link_libraries(${COMPONENT_LIB} --coverage) diff --git a/components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp b/components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp new file mode 100644 index 000000000..d3899be78 --- /dev/null +++ b/components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp @@ -0,0 +1,934 @@ +/* Hello World Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include "unity.h" +#include "test_fixtures.hpp" + +extern "C" { +#include "Mockesp_partition.h" +} + +using namespace std; +using namespace nvs; + +void test_Page_load_reading_header_fails() +{ + PartitionMock mock(0, 4096); + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_ARG); + Page page; + + TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state()); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, page.load(&mock, 0)); +} + +void test_Page_load_reading_data_fails() +{ + uint8_t header[64]; + std::fill_n(header, sizeof(header)/sizeof(header[0]), UINT8_MAX); + PartitionMock mock(0, 4096); + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(header, 32); + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_FAIL); + Page page; + + TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state()); + TEST_ASSERT_EQUAL(ESP_FAIL, page.load(&mock, 0)); +} + +void test_Page_load__uninitialized_page_has_0xfe() +{ + PartitionMockFixture fix; + Page page; + + fix.raw_header[511] = 0xfe; + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 32); + + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 512); + + // Page::load() should return ESP_OK, but state has to be corrupt + TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0)); + + TEST_ASSERT_EQUAL(Page::PageState::CORRUPT, page.state()); +} + +void test_Page_load__initialized_corrupt_header() +{ + PartitionMockFixture fix; + Page page; + + uint8_t raw_header_corrupt [] = {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x16, 0xdd, 0xdc}; + + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_corrupt, 32); + + // Page::load() should return ESP_OK, but state has to be corrupt + TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0)); + + TEST_ASSERT_EQUAL(Page::PageState::CORRUPT, page.state()); +} + +void test_Page_load_success() +{ + PartitionMockFixture fix; + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 32); + for (int i = 0; i < 8; i++) { + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 512); + } + Page page; + + TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state()); + TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0)); + TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, page.state()); +} + +void test_Page_load_full_page() +{ + NVSFullPageFixture fix(0, 1, NVS_DEFAULT_PART_NAME, false); + + TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state()); + TEST_ASSERT_EQUAL(ESP_OK, fix.page.load(&fix.part_mock, 0)); + TEST_ASSERT_EQUAL(Page::PageState::FULL, fix.page.state()); +} +void test_Page_load__seq_number_0() +{ + NVSValidPageFixture fix; + + uint32_t seq_num; + fix.page.getSeqNumber(seq_num); + TEST_ASSERT_EQUAL(0, seq_num); +} + +void test_Page_erase__write_fail() +{ + NVSValidPageFixture fix; + + esp_partition_erase_range_ExpectAndReturn(&fix.part_mock.partition, 0, 4096, ESP_FAIL); + + TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.erase()); + TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state()); +} + +void test_Page_erase__success() +{ + NVSValidPageFixture fix; + + esp_partition_erase_range_ExpectAndReturn(&fix.part_mock.partition, 0, 4096, ESP_OK); + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.erase()); + TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state()); +} + +void test_Page_write__initialize_write_failure() +{ + PartitionMockFixture fix; + uint8_t write_data = 47; + + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 32); + for (int i = 0; i < 8; i++) { + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 512); + } + esp_partition_write_raw_ExpectAnyArgsAndReturn(ESP_FAIL); + + Page page; + + TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0)); + TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, page.state()); + + TEST_ASSERT_EQUAL(ESP_FAIL, page.writeItem(1, nvs::ItemType::U8, "test", &write_data, sizeof(write_data))); + TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state()); +} + +void test_Page_write__write_data_fails() +{ + NVSPageFixture fix; + uint8_t write_data = 47; + esp_partition_write_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_write_ExpectAnyArgsAndReturn(ESP_FAIL); + + TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state()); + + TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.writeItem(1, nvs::ItemType::U8, "test", &write_data, sizeof(write_data))); + + TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state()); +} + +void test_page_write__write_correct_entry_state() +{ + NVSPageFixture fix; + uint8_t write_data = 47; + uint8_t raw_result [4]; + std::fill_n(raw_result, sizeof(raw_result)/sizeof(raw_result[0]), UINT8_MAX); + // mark first entry as written + raw_result[0] = 0xfe; + + // initialize page + esp_partition_write_raw_ExpectAnyArgsAndReturn(ESP_OK); + + // write entry + esp_partition_write_ExpectAnyArgsAndReturn(ESP_OK); + + // write entry state + esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_OK); + + TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state()); + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, nvs::ItemType::U8, "test_key", &write_data, sizeof(write_data))); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); +} + +void test_Page_write__write_correct_data() +{ + NVSPageFixture fix; + uint8_t write_data = 47; + uint8_t raw_result [32] = {0x01, 0x01, 0x01, 0xff, 0x98, 0x6f, 0x21, 0xfd, 't', 'e', 's', 't', '_', 'k', 'e', 'y', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + // initialize page + esp_partition_write_raw_ExpectAnyArgsAndReturn(ESP_OK); + + // write entry + esp_partition_write_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 64, raw_result, 32, 32, ESP_OK); + + // write entry state + esp_partition_write_raw_ExpectAnyArgsAndReturn(ESP_OK); + + TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state()); + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, nvs::ItemType::U8, "test_key", &write_data, sizeof(write_data))); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); +} + +void test_Page_readItem__read_entry_fails() +{ + NVSValidPageFixture fix; + + TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + + uint8_t read_value = 0; + + esp_partition_read_ExpectAnyArgsAndReturn(ESP_FAIL); + + TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.readItem(NVSValidPageFixture::NS_INDEX, "test_value", read_value)); + + TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state()); + + TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount()); +} + +void test_Page_readItem__read_corrupted_entry() +{ + NVSValidPageFixture fix; + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount()); + + uint8_t read_value = 0; + + // corrupting entry + fix.value_entry[0] = 0x0; + + // first read the entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + // Page::eraseEntryAndSpan() reads entry again + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + // erasing entry by setting bit in entry table (0xfa -> 0xf2) + uint8_t raw_result [4] = {0xf2, 0x00, 0x00, 0x00}; + esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_OK); + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, fix.page.readItem(NVSValidPageFixture::NS_INDEX, "test_value", read_value)); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + + TEST_ASSERT_EQUAL(1, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(123, fix.page.getErasedEntryCount()); +} + +void test_Page_readItem__read_corrupted_second_read_fail() +{ + NVSValidPageFixture fix; + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount()); + + uint8_t read_value = 0; + + // corrupting entry + fix.value_entry[0] = 0x0; + + // first read the entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + // Page::eraseEntryAndSpan() reads entry again + esp_partition_read_ExpectAnyArgsAndReturn(ESP_FAIL); + + TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.readItem(NVSValidPageFixture::NS_INDEX, "test_value", read_value)); + + TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state()); +} + +void test_Page_readItem__read_corrupted_erase_fail() +{ + NVSValidPageFixture fix; + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount()); + + uint8_t read_value = 0; + + // corrupting entry + fix.value_entry[0] = 0x0; + + // first read the entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + // Page::eraseEntryAndSpan() reads entry again + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + // erasing entry by setting bit in entry table (0xfa -> 0xf2) + uint8_t raw_result [4] = {0xf2, 0x00, 0x00, 0x00}; + esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_FAIL); + + TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.readItem(NVSValidPageFixture::NS_INDEX, "test_value", read_value)); + + TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state()); +} + +void test_Page_readItem__read_entry_suceeds() +{ + NVSValidPageFixture fix; + TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + + uint8_t read_value = 0; + + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.readItem(NVSValidPageFixture::NS_INDEX, "test_value", read_value)); + + TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(47, read_value); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); +} + +void test_Page_readItem__blob_read_data_fails() +{ + NVSValidBlobPageFixture fix; + TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + + uint8_t chunk_start = 0; + uint8_t read_data [32]; + + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32); + esp_partition_read_ExpectAnyArgsAndReturn(ESP_FAIL); + + TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.readItem(NVSValidPageFixture::NS_INDEX, + ItemType::BLOB_DATA, + "test_blob", + read_data, + 32, + chunk_start)); + + TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); +} + +void test_Page_readItem__corrupt_data_erase_failure() +{ + NVSValidBlobPageFixture fix; + TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + + uint8_t chunk_start = 0; + uint8_t read_data [32]; + + fix.blob_data[16] = 0xdf; + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32); + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE); + + // Page::eraseEntryAndSpan() reads entry again + esp_partition_read_ExpectAnyArgsAndReturn(ESP_FAIL); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE); + + TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.readItem(NVSValidPageFixture::NS_INDEX, + ItemType::BLOB_DATA, + "test_blob", + read_data, + 32, + chunk_start)); + + TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); +} + +void test_Page_readItem__blob_corrupt_data() +{ + NVSValidBlobPageFixture fix; + TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + + uint8_t chunk_start = 0; + uint8_t read_data [32]; + + fix.blob_data[16] = 0xdf; + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32); + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE); + + // Page::eraseEntryAndSpan() reads entry again + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE); + + // erasing entry by setting bit in entry table (0xfa -> 0xf2) + uint8_t raw_result [4] = {0xa2, 0xff, 0xff, 0xff}; + esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_OK); + + esp_partition_erase_range_ExpectAndReturn(&fix.part_mock.partition, 96, 64, ESP_OK); + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, fix.page.readItem(NVSValidPageFixture::NS_INDEX, + ItemType::BLOB_DATA, + "test_blob", + read_data, + 32, + chunk_start)); + + TEST_ASSERT_EQUAL(3, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(1, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); +} + +void test_Page_readItem__blob_read_entry_suceeds() +{ + NVSValidBlobPageFixture fix; + TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + + uint8_t chunk_start = 0; + uint8_t read_data [32]; + + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32); + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE); + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.readItem(NVSValidPageFixture::NS_INDEX, + ItemType::BLOB_DATA, + "test_blob", + read_data, + 32, + chunk_start)); + + TEST_ASSERT_EQUAL_MEMORY(fix.blob_data, read_data, fix.BLOB_DATA_SIZE); + + // make sure nothing was erased, i.e. checksums matched + TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); +} + +void test_Page_cmp__uninitialized() +{ + Page page; + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_INVALID_STATE, page.cmpItem(uint8_t(1) , "test", 47)); +} + +void test_Page_cmp__item_not_found() +{ + NVSValidPageFixture fix; + + // no expectations here since comparison uses the item hash list + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, fix.page.cmpItem(uint8_t(1), "different", 47)); +} + +void test_Page_cmp__item_type_mismatch() +{ + NVSValidPageFixture fix; + + // read normal entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.cmpItem(uint8_t(1), "test_value", int(47))); +} + +void test_Page_cmp__item_content_mismatch() +{ + NVSValidPageFixture fix; + + // read normal entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_CONTENT_DIFFERS, fix.page.cmpItem(uint8_t(1), "test_value", uint8_t(46))); +} + +void test_Page_cmp__item_content_match() +{ + NVSValidPageFixture fix; + + // read normal entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.cmpItem(NVSValidPageFixture::NS_INDEX, "test_value", uint8_t(47))); +} + +void test_Page_cmpItem__blob_data_mismatch() +{ + NVSValidBlobPageFixture fix; + + // read blob entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32); + + // read blob data + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE); + + + uint8_t blob_data_different [] = + {0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xee}; + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_CONTENT_DIFFERS, + fix.page.cmpItem(uint8_t(1), + ItemType::BLOB_DATA, + "test_blob", + blob_data_different, + 32)); +} + +void test_Page_cmpItem__blob_data_match() +{ + NVSValidBlobPageFixture fix; + + // read blob entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32); + + // read blob data + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE); + + + uint8_t blob_data_same [] = + {0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}; + + TEST_ASSERT_EQUAL(ESP_OK, + fix.page.cmpItem(NVSValidPageFixture::NS_INDEX, + ItemType::BLOB_DATA, + "test_blob", + blob_data_same, + 32)); +} + +void test_Page_eraseItem__uninitialized() +{ + Page page; + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, page.eraseItem(NVSValidPageFixture::NS_INDEX, "test_value")); +} + +void test_Page_eraseItem__key_not_found() +{ + NVSValidPageFixture fix; + TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, fix.page.eraseItem(NVSValidPageFixture::NS_INDEX, "different")); + + TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); +} + +void test_Page_eraseItem__write_fail() +{ + NVSValidPageFixture fix; + TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + + // first read the entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + // Page::eraseEntryAndSpan() reads entry again + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + // erasing entry by setting bit in entry table (0xfa -> 0xf2) + uint8_t raw_result [4] = {0xf2, 0x00, 0x00, 0x00}; + esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_FAIL); + + TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.eraseItem(NVSValidPageFixture::NS_INDEX, "test_value")); + + TEST_ASSERT_EQUAL(1, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(123, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state()); +} + +void test_Page_eraseItem__write_succeed() +{ + NVSValidPageFixture fix; + TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); + + // first read the entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + // Page::eraseEntryAndSpan() reads entry again + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + // erasing entry by setting bit in entry table (0xfa -> 0xf2) + uint8_t raw_result [4] = {0xf2, 0x00, 0x00, 0x00}; + esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_OK); + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.eraseItem(NVSValidPageFixture::NS_INDEX, "test_value")); + + TEST_ASSERT_EQUAL(1, fix.page.getUsedEntryCount()); + TEST_ASSERT_EQUAL(123, fix.page.getErasedEntryCount()); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state()); +} + +void test_Page_findItem__uninitialized() +{ + Page page; + + size_t index = 0; + Item item; + TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, + page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::U8, "test_value", index, item)); +} + +void test_Page_find__wrong_ns() +{ + NVSValidPageFixture fix; + size_t index = 0; + Item item; + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, + fix.page.findItem(NVSValidPageFixture::NS_INDEX + 1, nvs::ItemType::U8, "test_value", index, item)); +} + +void test_Page_find__wrong_type() +{ + NVSValidPageFixture fix; + size_t index = 0; + Item item; + + // read normal entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32); + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, + fix.page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::I8, "test_value", index, item)); +} + +void test_Page_find__key_empty() +{ + NVSValidPageFixture fix; + size_t index = 0; + Item item; + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, + fix.page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::U8, "", index, item)); +} + +void test_Page_find__wrong_key() +{ + NVSValidPageFixture fix; + size_t index = 0; + Item item; + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, + fix.page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::U8, "different", index, item)); +} + +void test_Page_find__too_large_index() +{ + NVSValidPageFixture fix; + size_t index = 2; + Item item; + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, + fix.page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::U8, "test_value", index, item)); +} + +void test_Page_findItem__without_read() +{ + NVSValidPageFixture fix; + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, + fix.page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::U8, "different")); +} + +void test_Page_markFull__wrong_state() +{ + NVSPageFixture fix; + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_INVALID_STATE, fix.page.markFull()); + TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state()); +} + +void test_Page_markFull__success() +{ + NVSValidPageFixture fix; + Page::PageState expected_state = Page::PageState::FULL; + + esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, sizeof(fix.part_mock.partition), 0, &expected_state, sizeof(expected_state), 4, ESP_OK); + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.markFull()); + TEST_ASSERT_EQUAL(Page::PageState::FULL, fix.page.state()); +} + +void test_Page_markFull__write_fail() +{ + NVSValidPageFixture fix; + Page::PageState expected_state = Page::PageState::FREEING; + + esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, sizeof(fix.part_mock.partition), 0, &expected_state, sizeof(expected_state), 4, ESP_FAIL); + + TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.markFreeing()); + TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state()); +} + +void test_Page_markFreeing__wrong_state() +{ + NVSPageFixture fix; + + TEST_ASSERT_EQUAL(ESP_ERR_NVS_INVALID_STATE, fix.page.markFreeing()); + TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state()); +} + +void test_Page_markFreeing__success() +{ + NVSValidPageFixture fix; + Page::PageState expected_state = Page::PageState::FREEING; + + esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, sizeof(fix.part_mock.partition), 0, &expected_state, sizeof(expected_state), 4, ESP_OK); + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.markFreeing()); + TEST_ASSERT_EQUAL(Page::PageState::FREEING, fix.page.state()); +} + +void test_Page_getVarDataTailroom__uninitialized_page() +{ + NVSPageFixture fix; + + TEST_ASSERT_EQUAL(Page::CHUNK_MAX_SIZE, fix.page.getVarDataTailroom()); +} + +void test_Page_getVarDataTailroom__success() +{ + NVSValidPageFixture fix; + + // blob data item, written namespace item, written normal item: 3 items + TEST_ASSERT_EQUAL((Page::ENTRY_COUNT - 3) * Page::ENTRY_SIZE, fix.page.getVarDataTailroom()); +} + +void test_Page_calcEntries__uninit() +{ + NVSPageFixture fix; + TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state()); + + nvs_stats_t nvsStats = {0, 0, 0, 0}; + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.calcEntries(nvsStats)); + TEST_ASSERT_EQUAL(0, nvsStats.used_entries); + TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.free_entries); + TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.total_entries); + TEST_ASSERT_EQUAL(0, nvsStats.namespace_count); +} + +void test_Page_calcEntries__corrupt() +{ + PartitionMockFixture fix; + Page page; + + uint8_t raw_header_corrupt [] = {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x16, 0xdd, 0xdc}; + + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_corrupt, 32); + + // Page::load() should return ESP_OK, but state has to be corrupt + TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0)); + + TEST_ASSERT_EQUAL(Page::PageState::CORRUPT, page.state()); + + nvs_stats_t nvsStats = {0, 0, 0, 0}; + + TEST_ASSERT_EQUAL(ESP_OK, page.calcEntries(nvsStats)); + TEST_ASSERT_EQUAL(0, nvsStats.used_entries); + TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.free_entries); + TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.total_entries); + TEST_ASSERT_EQUAL(0, nvsStats.namespace_count); +} + +void test_Page_calcEntries__active_wo_blob() +{ + NVSValidPageFixture fix; + + nvs_stats_t nvsStats = {0, 0, 0, 0}; + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.calcEntries(nvsStats)); + TEST_ASSERT_EQUAL(2, nvsStats.used_entries); + TEST_ASSERT_EQUAL(124, nvsStats.free_entries); + TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.total_entries); + TEST_ASSERT_EQUAL(0, nvsStats.namespace_count); +} + +void test_Page_calcEntries__active_with_blob() +{ + NVSValidBlobPageFixture fix; + + nvs_stats_t nvsStats = {0, 0, 0, 0}; + + TEST_ASSERT_EQUAL(ESP_OK, fix.page.calcEntries(nvsStats)); + TEST_ASSERT_EQUAL(4, nvsStats.used_entries); + TEST_ASSERT_EQUAL(122, nvsStats.free_entries); + TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.total_entries); + TEST_ASSERT_EQUAL(0, nvsStats.namespace_count); +} + +void test_Page_calcEntries__invalid() +{ + Page page; + + nvs_stats_t nvsStats = {0, 0, 0, 0}; + + TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state()); + + // total entries always get updated + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, page.calcEntries(nvsStats)); + TEST_ASSERT_EQUAL(0, nvsStats.used_entries); + TEST_ASSERT_EQUAL(0, nvsStats.free_entries); + TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.total_entries); + TEST_ASSERT_EQUAL(0, nvsStats.namespace_count); +} + +int main(int argc, char **argv) +{ + UNITY_BEGIN(); + RUN_TEST(test_Page_load_reading_header_fails); + RUN_TEST(test_Page_load_reading_data_fails); + RUN_TEST(test_Page_load__uninitialized_page_has_0xfe); + RUN_TEST(test_Page_load__initialized_corrupt_header); + RUN_TEST(test_Page_load_success); + RUN_TEST(test_Page_load_full_page); + RUN_TEST(test_Page_load__seq_number_0); + RUN_TEST(test_Page_erase__write_fail); + RUN_TEST(test_Page_erase__success); + RUN_TEST(test_Page_write__initialize_write_failure); + RUN_TEST(test_Page_write__write_data_fails); + RUN_TEST(test_page_write__write_correct_entry_state); + RUN_TEST(test_Page_write__write_correct_data); + RUN_TEST(test_Page_readItem__read_entry_fails); + RUN_TEST(test_Page_readItem__read_corrupted_entry); + RUN_TEST(test_Page_readItem__read_corrupted_second_read_fail); + RUN_TEST(test_Page_readItem__read_corrupted_erase_fail); + RUN_TEST(test_Page_readItem__read_entry_suceeds); + RUN_TEST(test_Page_readItem__blob_read_data_fails); + RUN_TEST(test_Page_readItem__blob_corrupt_data); + RUN_TEST(test_Page_readItem__blob_read_entry_suceeds); + RUN_TEST(test_Page_cmp__uninitialized); + RUN_TEST(test_Page_cmp__item_not_found); + RUN_TEST(test_Page_cmp__item_type_mismatch); + RUN_TEST(test_Page_cmp__item_content_mismatch); + RUN_TEST(test_Page_cmp__item_content_match); + RUN_TEST(test_Page_cmpItem__blob_data_mismatch); + RUN_TEST(test_Page_cmpItem__blob_data_match); + RUN_TEST(test_Page_eraseItem__uninitialized); + RUN_TEST(test_Page_eraseItem__key_not_found); + RUN_TEST(test_Page_eraseItem__write_fail); + RUN_TEST(test_Page_readItem__corrupt_data_erase_failure); + RUN_TEST(test_Page_eraseItem__write_succeed); + RUN_TEST(test_Page_findItem__uninitialized); + RUN_TEST(test_Page_find__wrong_ns); + RUN_TEST(test_Page_find__wrong_type); + RUN_TEST(test_Page_find__key_empty); + RUN_TEST(test_Page_find__wrong_key); + RUN_TEST(test_Page_find__too_large_index); + RUN_TEST(test_Page_findItem__without_read); + RUN_TEST(test_Page_markFull__wrong_state); + RUN_TEST(test_Page_markFreeing__wrong_state); + RUN_TEST(test_Page_markFull__success); + RUN_TEST(test_Page_markFreeing__success); + RUN_TEST(test_Page_markFull__write_fail); + RUN_TEST(test_Page_getVarDataTailroom__uninitialized_page); + RUN_TEST(test_Page_getVarDataTailroom__success); + RUN_TEST(test_Page_calcEntries__uninit); + RUN_TEST(test_Page_calcEntries__corrupt); + RUN_TEST(test_Page_calcEntries__active_wo_blob); + RUN_TEST(test_Page_calcEntries__active_with_blob); + RUN_TEST(test_Page_calcEntries__invalid); + UNITY_END(); + return 0; +} diff --git a/components/nvs_flash/host_test/nvs_page_test/sdkconfig.defaults b/components/nvs_flash/host_test/nvs_page_test/sdkconfig.defaults new file mode 100644 index 000000000..a05773334 --- /dev/null +++ b/components/nvs_flash/host_test/nvs_page_test/sdkconfig.defaults @@ -0,0 +1,3 @@ +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n +CONFIG_IDF_TARGET="linux" +CONFIG_CXX_EXCEPTIONS=y diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index dfdd18c92..26183853b 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -17,6 +17,7 @@ #include #include #include +#include "esp_attr.h" #include "esp_err.h" #ifdef __cplusplus @@ -26,34 +27,92 @@ extern "C" { /** * Opaque pointer type representing non-volatile storage handle */ -typedef uint32_t nvs_handle; - -#define ESP_ERR_NVS_BASE 0x1100 /*!< Starting number of error codes */ -#define ESP_ERR_NVS_NOT_INITIALIZED (ESP_ERR_NVS_BASE + 0x01) /*!< The storage driver is not initialized */ -#define ESP_ERR_NVS_NOT_FOUND (ESP_ERR_NVS_BASE + 0x02) /*!< Id namespace doesn’t exist yet and mode is NVS_READONLY */ -#define ESP_ERR_NVS_TYPE_MISMATCH (ESP_ERR_NVS_BASE + 0x03) /*!< The type of set or get operation doesn't match the type of value stored in NVS */ -#define ESP_ERR_NVS_READ_ONLY (ESP_ERR_NVS_BASE + 0x04) /*!< Storage handle was opened as read only */ -#define ESP_ERR_NVS_NOT_ENOUGH_SPACE (ESP_ERR_NVS_BASE + 0x05) /*!< There is not enough space in the underlying storage to save the value */ -#define ESP_ERR_NVS_INVALID_NAME (ESP_ERR_NVS_BASE + 0x06) /*!< Namespace name doesn’t satisfy constraints */ -#define ESP_ERR_NVS_INVALID_HANDLE (ESP_ERR_NVS_BASE + 0x07) /*!< Handle has been closed or is NULL */ -#define ESP_ERR_NVS_REMOVE_FAILED (ESP_ERR_NVS_BASE + 0x08) /*!< The value wasn’t updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn’t fail again. */ -#define ESP_ERR_NVS_KEY_TOO_LONG (ESP_ERR_NVS_BASE + 0x09) /*!< Key name is too long */ -#define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< Internal error; never returned by nvs_ API functions */ -#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< NVS is in an inconsistent state due to a previous error. Call nvs_flash_init and nvs_open again, then retry. */ -#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< String or blob length is not sufficient to store data */ -#define ESP_ERR_NVS_NO_FREE_PAGES (ESP_ERR_NVS_BASE + 0x0d) /*!< NVS partition doesn't contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again. */ -#define ESP_ERR_NVS_VALUE_TOO_LONG (ESP_ERR_NVS_BASE + 0x0e) /*!< String or blob length is longer than supported by the implementation */ -#define ESP_ERR_NVS_PART_NOT_FOUND (ESP_ERR_NVS_BASE + 0x0f) /*!< Partition with specified name is not found in the partition table */ - -#define NVS_DEFAULT_PART_NAME "nvs" /*!< Default partition name of the NVS partition in the partition table */ +typedef uint32_t nvs_handle_t; + +/* + * Pre-IDF V4.0 uses nvs_handle, so leaving the original typedef here for compatibility. + */ +typedef nvs_handle_t nvs_handle IDF_DEPRECATED("Replace with nvs_handle_t"); + +#define ESP_ERR_NVS_BASE 0x1100 /*!< Starting number of error codes */ +#define ESP_ERR_NVS_NOT_INITIALIZED (ESP_ERR_NVS_BASE + 0x01) /*!< The storage driver is not initialized */ +#define ESP_ERR_NVS_NOT_FOUND (ESP_ERR_NVS_BASE + 0x02) /*!< Id namespace doesn’t exist yet and mode is NVS_READONLY */ +#define ESP_ERR_NVS_TYPE_MISMATCH (ESP_ERR_NVS_BASE + 0x03) /*!< The type of set or get operation doesn't match the type of value stored in NVS */ +#define ESP_ERR_NVS_READ_ONLY (ESP_ERR_NVS_BASE + 0x04) /*!< Storage handle was opened as read only */ +#define ESP_ERR_NVS_NOT_ENOUGH_SPACE (ESP_ERR_NVS_BASE + 0x05) /*!< There is not enough space in the underlying storage to save the value */ +#define ESP_ERR_NVS_INVALID_NAME (ESP_ERR_NVS_BASE + 0x06) /*!< Namespace name doesn’t satisfy constraints */ +#define ESP_ERR_NVS_INVALID_HANDLE (ESP_ERR_NVS_BASE + 0x07) /*!< Handle has been closed or is NULL */ +#define ESP_ERR_NVS_REMOVE_FAILED (ESP_ERR_NVS_BASE + 0x08) /*!< The value wasn’t updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn’t fail again. */ +#define ESP_ERR_NVS_KEY_TOO_LONG (ESP_ERR_NVS_BASE + 0x09) /*!< Key name is too long */ +#define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< Internal error; never returned by nvs API functions */ +#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< NVS is in an inconsistent state due to a previous error. Call nvs_flash_init and nvs_open again, then retry. */ +#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< String or blob length is not sufficient to store data */ +#define ESP_ERR_NVS_NO_FREE_PAGES (ESP_ERR_NVS_BASE + 0x0d) /*!< NVS partition doesn't contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again. */ +#define ESP_ERR_NVS_VALUE_TOO_LONG (ESP_ERR_NVS_BASE + 0x0e) /*!< String or blob length is longer than supported by the implementation */ +#define ESP_ERR_NVS_PART_NOT_FOUND (ESP_ERR_NVS_BASE + 0x0f) /*!< Partition with specified name is not found in the partition table */ + +#define ESP_ERR_NVS_NEW_VERSION_FOUND (ESP_ERR_NVS_BASE + 0x10) /*!< NVS partition contains data in new format and cannot be recognized by this version of code */ +#define ESP_ERR_NVS_XTS_ENCR_FAILED (ESP_ERR_NVS_BASE + 0x11) /*!< XTS encryption failed while writing NVS entry */ +#define ESP_ERR_NVS_XTS_DECR_FAILED (ESP_ERR_NVS_BASE + 0x12) /*!< XTS decryption failed while reading NVS entry */ +#define ESP_ERR_NVS_XTS_CFG_FAILED (ESP_ERR_NVS_BASE + 0x13) /*!< XTS configuration setting failed */ +#define ESP_ERR_NVS_XTS_CFG_NOT_FOUND (ESP_ERR_NVS_BASE + 0x14) /*!< XTS configuration not found */ +#define ESP_ERR_NVS_ENCR_NOT_SUPPORTED (ESP_ERR_NVS_BASE + 0x15) /*!< NVS encryption is not supported in this version */ +#define ESP_ERR_NVS_KEYS_NOT_INITIALIZED (ESP_ERR_NVS_BASE + 0x16) /*!< NVS key partition is uninitialized */ +#define ESP_ERR_NVS_CORRUPT_KEY_PART (ESP_ERR_NVS_BASE + 0x17) /*!< NVS key partition is corrupt */ +#define ESP_ERR_NVS_WRONG_ENCRYPTION (ESP_ERR_NVS_BASE + 0x19) /*!< NVS partition is marked as encrypted with generic flash encryption. This is forbidden since the NVS encryption works differently. */ + +#define ESP_ERR_NVS_CONTENT_DIFFERS (ESP_ERR_NVS_BASE + 0x18) /*!< Internal error; never returned by nvs API functions. NVS key is different in comparison */ + +#define NVS_DEFAULT_PART_NAME "nvs" /*!< Default partition name of the NVS partition in the partition table */ + +#define NVS_PART_NAME_MAX_SIZE 16 /*!< maximum length of partition name (excluding null terminator) */ +#define NVS_KEY_NAME_MAX_SIZE 16 /*!< Maximal length of NVS key name (including null terminator) */ + /** * @brief Mode of opening the non-volatile storage - * */ typedef enum { NVS_READONLY, /*!< Read only */ NVS_READWRITE /*!< Read and write */ -} nvs_open_mode; +} nvs_open_mode_t; + +/* + * Pre-IDF V4.0 uses nvs_open_mode, so leaving the original typedef here for compatibility. + */ +typedef nvs_open_mode_t nvs_open_mode IDF_DEPRECATED("Replace with nvs_open_mode_t"); + + +/** + * @brief Types of variables + * + */ +typedef enum { + NVS_TYPE_U8 = 0x01, /*!< Type uint8_t */ + NVS_TYPE_I8 = 0x11, /*!< Type int8_t */ + NVS_TYPE_U16 = 0x02, /*!< Type uint16_t */ + NVS_TYPE_I16 = 0x12, /*!< Type int16_t */ + NVS_TYPE_U32 = 0x04, /*!< Type uint32_t */ + NVS_TYPE_I32 = 0x14, /*!< Type int32_t */ + NVS_TYPE_U64 = 0x08, /*!< Type uint64_t */ + NVS_TYPE_I64 = 0x18, /*!< Type int64_t */ + NVS_TYPE_STR = 0x21, /*!< Type string */ + NVS_TYPE_BLOB = 0x42, /*!< Type blob */ + NVS_TYPE_ANY = 0xff /*!< Must be last */ +} nvs_type_t; + +/** + * @brief information about entry obtained from nvs_entry_info function + */ +typedef struct { + char namespace_name[16]; /*!< Namespace to which key-value belong */ + char key[16]; /*!< Key of stored key-value pair */ + nvs_type_t type; /*!< Type of stored key-value pair */ +} nvs_entry_info_t; + +/** + * Opaque pointer type representing iterator to nvs entries + */ +typedef struct nvs_opaque_iterator_t *nvs_iterator_t; /** * @brief Open non-volatile storage with a given namespace from the default NVS partition @@ -64,12 +123,10 @@ typedef enum { * The default NVS partition is the one that is labelled "nvs" in the partition * table. * - * @param[in] name Namespace name. Maximal length is determined by the - * underlying implementation, but is guaranteed to be - * at least 15 characters. Shouldn't be empty. + * @param[in] name Namespace name. Maximal length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. * @param[in] open_mode NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will * open a handle for reading only. All write requests will - * be rejected for this handle. + * be rejected for this handle. * @param[out] out_handle If successful (return code is zero), handle will be * returned in this argument. * @@ -80,9 +137,10 @@ typedef enum { * - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and * mode is NVS_READONLY * - ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints + * - ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures * - other error codes from the underlying storage driver */ -esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle); +esp_err_t nvs_open(const char* name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle); /** * @brief Open non-volatile storage with a given namespace from specified partition @@ -92,12 +150,10 @@ esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_ha * with NVS using nvs_flash_init_partition() API. * * @param[in] part_name Label (name) of the partition of interest for object read/write/erase - * @param[in] name Namespace name. Maximal length is determined by the - * underlying implementation, but is guaranteed to be - * at least 15 characters. Shouldn't be empty. - * @param[in] open_mode NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will - * open a handle for reading only. All write requests will - * be rejected for this handle. + * @param[in] name Namespace name. Maximal length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. + * @param[in] open_mode NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will + * open a handle for reading only. All write requests will + * be rejected for this handle. * @param[out] out_handle If successful (return code is zero), handle will be * returned in this argument. * @@ -108,25 +164,99 @@ esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_ha * - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and * mode is NVS_READONLY * - ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints + * - ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures * - other error codes from the underlying storage driver */ -esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode open_mode, nvs_handle *out_handle); +esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle); /**@{*/ /** - * @brief set value for given key + * @brief set int8_t value for given key * - * This family of functions set value for the key, given its name. Note that - * actual storage will not be updated until nvs_commit function is called. + * Set value for the key, given its name. Note that the actual storage will not be updated + * until \c nvs_commit is called. + * + * @param[in] handle Handle obtained from nvs_open function. + * Handles that were opened read only cannot be used. + * @param[in] key Key name. Maximal length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. + * @param[in] value The value to set. + * + * @return + * - ESP_OK if value was set successfully + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only + * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints + * - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the + * underlying storage to save the value + * - ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash + * write operation has failed. The value was written however, and + * update will be finished after re-initialization of nvs, provided that + * flash operation doesn't fail again. + */ +esp_err_t nvs_set_i8 (nvs_handle_t handle, const char* key, int8_t value); + +/** + * @brief set uint8_t value for given key + * + * This function is the same as \c nvs_set_i8 except for the data type. + */ +esp_err_t nvs_set_u8 (nvs_handle_t handle, const char* key, uint8_t value); + +/** + * @brief set int16_t value for given key + * + * This function is the same as \c nvs_set_i8 except for the data type. + */ +esp_err_t nvs_set_i16 (nvs_handle_t handle, const char* key, int16_t value); + +/** + * @brief set uint16_t value for given key + * + * This function is the same as \c nvs_set_i8 except for the data type. + */ +esp_err_t nvs_set_u16 (nvs_handle_t handle, const char* key, uint16_t value); + +/** + * @brief set int32_t value for given key + * + * This function is the same as \c nvs_set_i8 except for the data type. + */ +esp_err_t nvs_set_i32 (nvs_handle_t handle, const char* key, int32_t value); + +/** + * @brief set uint32_t value for given key + * + * This function is the same as \c nvs_set_i8 except for the data type. + */ +esp_err_t nvs_set_u32 (nvs_handle_t handle, const char* key, uint32_t value); + +/** + * @brief set int64_t value for given key + * + * This function is the same as \c nvs_set_i8 except for the data type. + */ +esp_err_t nvs_set_i64 (nvs_handle_t handle, const char* key, int64_t value); + +/** + * @brief set uint64_t value for given key + * + * This function is the same as \c nvs_set_i8 except for the data type. + */ +esp_err_t nvs_set_u64 (nvs_handle_t handle, const char* key, uint64_t value); + +/** + * @brief set string for given key + * + * Set value for the key, given its name. Note that the actual storage will not be updated + * until \c nvs_commit is called. * * @param[in] handle Handle obtained from nvs_open function. * Handles that were opened read only cannot be used. - * @param[in] key Key name. Maximal length is determined by the underlying - * implementation, but is guaranteed to be at least - * 15 characters. Shouldn't be empty. + * @param[in] key Key name. Maximal length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. * @param[in] value The value to set. * For strings, the maximum length (including null character) is - * 1984 bytes. + * 4000 bytes, if there is one complete page free for writing. + * This decreases, however, if the free space is fragmented. * * @return * - ESP_OK if value was set successfully @@ -141,16 +271,8 @@ esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_o * flash operation doesn't fail again. * - ESP_ERR_NVS_VALUE_TOO_LONG if the string value is too long */ -esp_err_t nvs_set_i8 (nvs_handle handle, const char* key, int8_t value); -esp_err_t nvs_set_u8 (nvs_handle handle, const char* key, uint8_t value); -esp_err_t nvs_set_i16 (nvs_handle handle, const char* key, int16_t value); -esp_err_t nvs_set_u16 (nvs_handle handle, const char* key, uint16_t value); -esp_err_t nvs_set_i32 (nvs_handle handle, const char* key, int32_t value); -esp_err_t nvs_set_u32 (nvs_handle handle, const char* key, uint32_t value); -esp_err_t nvs_set_i64 (nvs_handle handle, const char* key, int64_t value); -esp_err_t nvs_set_u64 (nvs_handle handle, const char* key, uint64_t value); -esp_err_t nvs_set_str (nvs_handle handle, const char* key, const char* value); -/**@}*/ +esp_err_t nvs_set_str (nvs_handle_t handle, const char* key, const char* value); +/**@}*/ /** * @brief set variable length binary value for given key @@ -160,10 +282,11 @@ esp_err_t nvs_set_str (nvs_handle handle, const char* key, const char* value); * * @param[in] handle Handle obtained from nvs_open function. * Handles that were opened read only cannot be used. - * @param[in] key Key name. Maximal length is 15 characters. Shouldn't be empty. + * @param[in] key Key name. Maximal length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. * @param[in] value The value to set. * @param[in] length length of binary value to set, in bytes; Maximum length is - * 1984 bytes. + * 508000 bytes or (97.6% of the partition size - 4000) bytes + * whichever is lower. * * @return * - ESP_OK if value was set successfully @@ -178,20 +301,19 @@ esp_err_t nvs_set_str (nvs_handle handle, const char* key, const char* value); * flash operation doesn't fail again. * - ESP_ERR_NVS_VALUE_TOO_LONG if the value is too long */ -esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length); +esp_err_t nvs_set_blob(nvs_handle_t handle, const char* key, const void* value, size_t length); /**@{*/ /** - * @brief get value for given key + * @brief get int8_t value for given key * - * These functions retrieve value for the key, given its name. If key does not + * These functions retrieve value for the key, given its name. If \c key does not * exist, or the requested variable type doesn't match the type which was used * when setting a value, an error is returned. * * In case of any error, out_value is not modified. * - * All functions expect out_value to be a pointer to an already allocated variable - * of the given type. + * \c out_value has to be a pointer to an already allocated variable of the given type. * * \code{c} * // Example of using nvs_get_i32: @@ -204,9 +326,7 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si * \endcode * * @param[in] handle Handle obtained from nvs_open function. - * @param[in] key Key name. Maximal length is determined by the underlying - * implementation, but is guaranteed to be at least - * 15 characters. Shouldn't be empty. + * @param[in] key Key name. Maximal length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. * @param out_value Pointer to the output value. * May be NULL for nvs_get_str and nvs_get_blob, in this * case required length will be returned in length argument. @@ -218,20 +338,63 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints * - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data */ -esp_err_t nvs_get_i8 (nvs_handle handle, const char* key, int8_t* out_value); -esp_err_t nvs_get_u8 (nvs_handle handle, const char* key, uint8_t* out_value); -esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value); -esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value); -esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value); -esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value); -esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value); -esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value); -/**@}*/ +esp_err_t nvs_get_i8 (nvs_handle_t handle, const char* key, int8_t* out_value); + +/** + * @brief get uint8_t value for given key + * + * This function is the same as \c nvs_get_i8 except for the data type. + */ +esp_err_t nvs_get_u8 (nvs_handle_t handle, const char* key, uint8_t* out_value); + +/** + * @brief get int16_t value for given key + * + * This function is the same as \c nvs_get_i8 except for the data type. + */ +esp_err_t nvs_get_i16 (nvs_handle_t handle, const char* key, int16_t* out_value); /** - * @brief get value for given key + * @brief get uint16_t value for given key * - * These functions retrieve value for the key, given its name. If key does not + * This function is the same as \c nvs_get_i8 except for the data type. + */ +esp_err_t nvs_get_u16 (nvs_handle_t handle, const char* key, uint16_t* out_value); + +/** + * @brief get int32_t value for given key + * + * This function is the same as \c nvs_get_i8 except for the data type. + */ +esp_err_t nvs_get_i32 (nvs_handle_t handle, const char* key, int32_t* out_value); + +/** + * @brief get uint32_t value for given key + * + * This function is the same as \c nvs_get_i8 except for the data type. + */ +esp_err_t nvs_get_u32 (nvs_handle_t handle, const char* key, uint32_t* out_value); + +/** + * @brief get int64_t value for given key + * + * This function is the same as \c nvs_get_i8 except for the data type. + */ +esp_err_t nvs_get_i64 (nvs_handle_t handle, const char* key, int64_t* out_value); + +/** + * @brief get uint64_t value for given key + * + * This function is the same as \c nvs_get_i8 except for the data type. + */ +esp_err_t nvs_get_u64 (nvs_handle_t handle, const char* key, uint64_t* out_value); +/**@}*/ + +/**@{*/ +/** + * @brief get string value for given key + * + * These functions retrieve the data of an entry, given its key. If key does not * exist, or the requested variable type doesn't match the type which was used * when setting a value, an error is returned. * @@ -239,7 +402,7 @@ esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value); * * All functions expect out_value to be a pointer to an already allocated variable * of the given type. - * + * * nvs_get_str and nvs_get_blob functions support WinAPI-style length queries. * To get the size necessary to store the value, call nvs_get_str or nvs_get_blob * with zero out_value and non-zero pointer to length. Variable pointed to @@ -265,10 +428,8 @@ esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value); * \endcode * * @param[in] handle Handle obtained from nvs_open function. - * @param[in] key Key name. Maximal length is determined by the underlying - * implementation, but is guaranteed to be at least - * 15 characters. Shouldn't be empty. - * @param out_value Pointer to the output value. + * @param[in] key Key name. Maximal length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. + * @param[out] out_value Pointer to the output value. * May be NULL for nvs_get_str and nvs_get_blob, in this * case required length will be returned in length argument. * @param[inout] length A non-zero pointer to the variable holding the length of out_value. @@ -282,11 +443,16 @@ esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value); * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints - * - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data + * - ESP_ERR_NVS_INVALID_LENGTH if \c length is not sufficient to store data */ -/**@{*/ -esp_err_t nvs_get_str (nvs_handle handle, const char* key, char* out_value, size_t* length); -esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length); +esp_err_t nvs_get_str (nvs_handle_t handle, const char* key, char* out_value, size_t* length); + +/** + * @brief get blob value for given key + * + * This function behaves the same as \c nvs_get_str, except for the data type. + */ +esp_err_t nvs_get_blob(nvs_handle_t handle, const char* key, void* out_value, size_t* length); /**@}*/ /** @@ -297,9 +463,7 @@ esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size * @param[in] handle Storage handle obtained with nvs_open. * Handles that were opened read only cannot be used. * - * @param[in] key Key name. Maximal length is determined by the underlying - * implementation, but is guaranteed to be at least - * 15 characters. Shouldn't be empty. + * @param[in] key Key name. Maximal length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. * * @return * - ESP_OK if erase operation was successful @@ -308,7 +472,7 @@ esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist * - other error codes from the underlying storage driver */ -esp_err_t nvs_erase_key(nvs_handle handle, const char* key); +esp_err_t nvs_erase_key(nvs_handle_t handle, const char* key); /** * @brief Erase all key-value pairs in a namespace @@ -324,7 +488,7 @@ esp_err_t nvs_erase_key(nvs_handle handle, const char* key); * - ESP_ERR_NVS_READ_ONLY if handle was opened as read only * - other error codes from the underlying storage driver */ -esp_err_t nvs_erase_all(nvs_handle handle); +esp_err_t nvs_erase_all(nvs_handle_t handle); /** * @brief Write any pending changes to non-volatile storage @@ -341,7 +505,7 @@ esp_err_t nvs_erase_all(nvs_handle handle); * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - other error codes from the underlying storage driver */ -esp_err_t nvs_commit(nvs_handle handle); +esp_err_t nvs_commit(nvs_handle_t handle); /** * @brief Close the storage handle and free any allocated resources @@ -354,7 +518,154 @@ esp_err_t nvs_commit(nvs_handle handle); * * @param[in] handle Storage handle to close */ -void nvs_close(nvs_handle handle); +void nvs_close(nvs_handle_t handle); + +/** + * @note Info about storage space NVS. + */ +typedef struct { + size_t used_entries; /**< Amount of used entries. */ + size_t free_entries; /**< Amount of free entries. */ + size_t total_entries; /**< Amount all available entries. */ + size_t namespace_count; /**< Amount name space. */ +} nvs_stats_t; + +/** + * @brief Fill structure nvs_stats_t. It provides info about used memory the partition. + * + * This function calculates to runtime the number of used entries, free entries, total entries, + * and amount namespace in partition. + * + * \code{c} + * // Example of nvs_get_stats() to get the number of used entries and free entries: + * nvs_stats_t nvs_stats; + * nvs_get_stats(NULL, &nvs_stats); + * printf("Count: UsedEntries = (%d), FreeEntries = (%d), AllEntries = (%d)\n", + nvs_stats.used_entries, nvs_stats.free_entries, nvs_stats.total_entries); + * \endcode + * + * @param[in] part_name Partition name NVS in the partition table. + * If pass a NULL than will use NVS_DEFAULT_PART_NAME ("nvs"). + * + * @param[out] nvs_stats Returns filled structure nvs_states_t. + * It provides info about used memory the partition. + * + * + * @return + * - ESP_OK if the changes have been written successfully. + * Return param nvs_stats will be filled. + * - ESP_ERR_NVS_PART_NOT_FOUND if the partition with label "name" is not found. + * Return param nvs_stats will be filled 0. + * - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized. + * Return param nvs_stats will be filled 0. + * - ESP_ERR_INVALID_ARG if nvs_stats equal to NULL. + * - ESP_ERR_INVALID_STATE if there is page with the status of INVALID. + * Return param nvs_stats will be filled not with correct values because + * not all pages will be counted. Counting will be interrupted at the first INVALID page. + */ +esp_err_t nvs_get_stats(const char *part_name, nvs_stats_t *nvs_stats); + +/** + * @brief Calculate all entries in a namespace. + * + * An entry represents the smallest storage unit in NVS. + * Strings and blobs may occupy more than one entry. + * Note that to find out the total number of entries occupied by the namespace, + * add one to the returned value used_entries (if err is equal to ESP_OK). + * Because the name space entry takes one entry. + * + * \code{c} + * // Example of nvs_get_used_entry_count() to get amount of all key-value pairs in one namespace: + * nvs_handle_t handle; + * nvs_open("namespace1", NVS_READWRITE, &handle); + * ... + * size_t used_entries; + * size_t total_entries_namespace; + * if(nvs_get_used_entry_count(handle, &used_entries) == ESP_OK){ + * // the total number of entries occupied by the namespace + * total_entries_namespace = used_entries + 1; + * } + * \endcode + * + * @param[in] handle Handle obtained from nvs_open function. + * + * @param[out] used_entries Returns amount of used entries from a namespace. + * + * + * @return + * - ESP_OK if the changes have been written successfully. + * Return param used_entries will be filled valid value. + * - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized. + * Return param used_entries will be filled 0. + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL. + * Return param used_entries will be filled 0. + * - ESP_ERR_INVALID_ARG if used_entries equal to NULL. + * - Other error codes from the underlying storage driver. + * Return param used_entries will be filled 0. + */ +esp_err_t nvs_get_used_entry_count(nvs_handle_t handle, size_t* used_entries); + +/** + * @brief Create an iterator to enumerate NVS entries based on one or more parameters + * + * \code{c} + * // Example of listing all the key-value pairs of any type under specified partition and namespace + * nvs_iterator_t it = nvs_entry_find(partition, namespace, NVS_TYPE_ANY); + * while (it != NULL) { + * nvs_entry_info_t info; + * nvs_entry_info(it, &info); + * it = nvs_entry_next(it); + * printf("key '%s', type '%d' \n", info.key, info.type); + * }; + * // Note: no need to release iterator obtained from nvs_entry_find function when + * // nvs_entry_find or nvs_entry_next function return NULL, indicating no other + * // element for specified criteria was found. + * } + * \endcode + * + * @param[in] part_name Partition name + * + * @param[in] namespace_name Set this value if looking for entries with + * a specific namespace. Pass NULL otherwise. + * + * @param[in] type One of nvs_type_t values. + * + * @return + * Iterator used to enumerate all the entries found, + * or NULL if no entry satisfying criteria was found. + * Iterator obtained through this function has to be released + * using nvs_release_iterator when not used any more. + */ +nvs_iterator_t nvs_entry_find(const char *part_name, const char *namespace_name, nvs_type_t type); + +/** + * @brief Returns next item matching the iterator criteria, NULL if no such item exists. + * + * Note that any copies of the iterator will be invalid after this call. + * + * @param[in] iterator Iterator obtained from nvs_entry_find function. Must be non-NULL. + * + * @return + * NULL if no entry was found, valid nvs_iterator_t otherwise. + */ +nvs_iterator_t nvs_entry_next(nvs_iterator_t iterator); + +/** + * @brief Fills nvs_entry_info_t structure with information about entry pointed to by the iterator. + * + * @param[in] iterator Iterator obtained from nvs_entry_find or nvs_entry_next function. Must be non-NULL. + * + * @param[out] out_info Structure to which entry information is copied. + */ +void nvs_entry_info(nvs_iterator_t iterator, nvs_entry_info_t *out_info); + +/** + * @brief Release iterator + * + * @param[in] iterator Release iterator obtained from nvs_entry_find function. NULL argument is allowed. + * + */ +void nvs_release_iterator(nvs_iterator_t iterator); #ifdef __cplusplus @@ -362,4 +673,3 @@ void nvs_close(nvs_handle handle); #endif #endif //ESP_NVS_H - diff --git a/components/nvs_flash/include/nvs_flash.h b/components/nvs_flash/include/nvs_flash.h index a7ef7f451..a5ad9ac28 100644 --- a/components/nvs_flash/include/nvs_flash.h +++ b/components/nvs_flash/include/nvs_flash.h @@ -19,6 +19,18 @@ extern "C" { #endif #include "nvs.h" +#include "esp_partition.h" + + +#define NVS_KEY_SIZE 32 // AES-256 + +/** + * @brief Key for encryption and decryption + */ +typedef struct { + uint8_t eky[NVS_KEY_SIZE]; /*!< XTS encryption and decryption key*/ + uint8_t tky[NVS_KEY_SIZE]; /*!< XTS tweak key */ +} nvs_sec_cfg_t; /** * @brief Initialize the default NVS partition. @@ -26,30 +38,62 @@ extern "C" { * This API initialises the default NVS partition. The default NVS partition * is the one that is labeled "nvs" in the partition table. * + * When "NVS_ENCRYPTION" is enabled in the menuconfig, this API enables + * the NVS encryption for the default NVS partition as follows + * 1. Read security configurations from the first NVS key + * partition listed in the partition table. (NVS key partition is + * any "data" type partition which has the subtype value set to "nvs_keys") + * 2. If the NVS key partiton obtained in the previous step is empty, + * generate and store new keys in that NVS key partiton. + * 3. Internally call "nvs_flash_secure_init()" with + * the security configurations obtained/generated in the previous steps. + * + * Post initialization NVS read/write APIs + * remain the same irrespective of NVS encryption. + * * @return * - ESP_OK if storage was successfully initialized. * - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages * (which may happen if NVS partition was truncated) * - ESP_ERR_NOT_FOUND if no partition with label "nvs" is found in the partition table + * - ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures * - one of the error codes from the underlying flash storage driver + * - error codes from nvs_flash_read_security_cfg API (when "NVS_ENCRYPTION" is enabled). + * - error codes from nvs_flash_generate_keys API (when "NVS_ENCRYPTION" is enabled). + * - error codes from nvs_flash_secure_init_partition API (when "NVS_ENCRYPTION" is enabled) . */ esp_err_t nvs_flash_init(void); /** * @brief Initialize NVS flash storage for the specified partition. * - * @param[in] partition_label Label of the partition. Note that internally a reference to - * passed value is kept and it should be accessible for future operations + * @param[in] partition_label Label of the partition. Must be no longer than 16 characters. * * @return * - ESP_OK if storage was successfully initialized. * - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages * (which may happen if NVS partition was truncated) * - ESP_ERR_NOT_FOUND if specified partition is not found in the partition table + * - ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures * - one of the error codes from the underlying flash storage driver */ esp_err_t nvs_flash_init_partition(const char *partition_label); +/** + * @brief Initialize NVS flash storage for the partition specified by partition pointer. + * + * @param[in] partition pointer to a partition obtained by the ESP partition API. + * + * @return + * - ESP_OK if storage was successfully initialized + * - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages + * (which may happen if NVS partition was truncated) + * - ESP_ERR_INVALID_ARG in case partition is NULL + * - ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures + * - one of the error codes from the underlying flash storage driver + */ +esp_err_t nvs_flash_init_partition_ptr(const esp_partition_t *partition); + /** * @brief Deinitialize NVS storage for the default NVS partition * @@ -76,29 +120,133 @@ esp_err_t nvs_flash_deinit_partition(const char* partition_label); /** * @brief Erase the default NVS partition * - * This function erases all contents of the default NVS partition (one with label "nvs") + * Erases all contents of the default NVS partition (one with label "nvs"). + * + * @note If the partition is initialized, this function first de-initializes it. Afterwards, the partition has to + * be initialized again to be used. * * @return * - ESP_OK on success * - ESP_ERR_NOT_FOUND if there is no NVS partition labeled "nvs" in the * partition table + * - different error in case de-initialization fails (shouldn't happen) */ esp_err_t nvs_flash_erase(void); /** * @brief Erase specified NVS partition * - * This function erases all contents of specified NVS partition + * Erase all content of a specified NVS partition * - * @param[in] part_name Name (label) of the partition to be erased + * @note If the partition is initialized, this function first de-initializes it. Afterwards, the partition has to + * be initialized again to be used. + * + * @param[in] part_name Name (label) of the partition which should be erased * * @return * - ESP_OK on success * - ESP_ERR_NOT_FOUND if there is no NVS partition with the specified name * in the partition table + * - different error in case de-initialization fails (shouldn't happen) */ esp_err_t nvs_flash_erase_partition(const char *part_name); +/** + * @brief Erase custom partition. + * + * Erase all content of specified custom partition. + * + * @note + * If the partition is initialized, this function first de-initializes it. + * Afterwards, the partition has to be initialized again to be used. + * + * @param[in] partition pointer to a partition obtained by the ESP partition API. + * + * @return + * - ESP_OK on success + * - ESP_ERR_NOT_FOUND if there is no partition with the specified + * parameters in the partition table + * - ESP_ERR_INVALID_ARG in case partition is NULL + * - one of the error codes from the underlying flash storage driver + */ +esp_err_t nvs_flash_erase_partition_ptr(const esp_partition_t *partition); + +/** + * @brief Initialize the default NVS partition. + * + * This API initialises the default NVS partition. The default NVS partition + * is the one that is labeled "nvs" in the partition table. + * + * @param[in] cfg Security configuration (keys) to be used for NVS encryption/decryption. + * If cfg is NULL, no encryption is used. + * + * @return + * - ESP_OK if storage was successfully initialized. + * - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages + * (which may happen if NVS partition was truncated) + * - ESP_ERR_NOT_FOUND if no partition with label "nvs" is found in the partition table + * - ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures + * - one of the error codes from the underlying flash storage driver + */ +esp_err_t nvs_flash_secure_init(nvs_sec_cfg_t* cfg); + +/** + * @brief Initialize NVS flash storage for the specified partition. + * + * @param[in] partition_label Label of the partition. Note that internally a reference to + * passed value is kept and it should be accessible for future operations + * + * @param[in] cfg Security configuration (keys) to be used for NVS encryption/decryption. + * If cfg is null, no encryption/decryption is used. + * @return + * - ESP_OK if storage was successfully initialized. + * - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages + * (which may happen if NVS partition was truncated) + * - ESP_ERR_NOT_FOUND if specified partition is not found in the partition table + * - ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures + * - one of the error codes from the underlying flash storage driver + */ +esp_err_t nvs_flash_secure_init_partition(const char *partition_label, nvs_sec_cfg_t* cfg); + +/** + * @brief Generate and store NVS keys in the provided esp partition + * + * @param[in] partition Pointer to partition structure obtained using + * esp_partition_find_first or esp_partition_get. + * Must be non-NULL. + * @param[out] cfg Pointer to nvs security configuration structure. + * Pointer must be non-NULL. + * Generated keys will be populated in this structure. + * + * + * @return + * -ESP_OK, if cfg was read successfully; + * -or error codes from esp_partition_write/erase APIs. + */ + +esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, nvs_sec_cfg_t* cfg); + + +/** + * @brief Read NVS security configuration from a partition. + * + * @param[in] partition Pointer to partition structure obtained using + * esp_partition_find_first or esp_partition_get. + * Must be non-NULL. + * @param[out] cfg Pointer to nvs security configuration structure. + * Pointer must be non-NULL. + * + * @note Provided parition is assumed to be marked 'encrypted'. + * + * @return + * -ESP_OK, if cfg was read successfully; + * -ESP_ERR_NVS_KEYS_NOT_INITIALIZED, if the partition is not yet written with keys. + * -ESP_ERR_NVS_CORRUPT_KEY_PART, if the partition containing keys is found to be corrupt + * -or error codes from esp_partition_read API. + */ + +esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partition, nvs_sec_cfg_t* cfg); + #ifdef __cplusplus } #endif diff --git a/components/nvs_flash/include/nvs_handle.hpp b/components/nvs_flash/include/nvs_handle.hpp new file mode 100644 index 000000000..287866fad --- /dev/null +++ b/components/nvs_flash/include/nvs_handle.hpp @@ -0,0 +1,280 @@ +#ifndef NVS_HANDLE_HPP_ +#define NVS_HANDLE_HPP_ + +#include +#include +#include + +#include "nvs.h" + +namespace nvs { + +/** + * The possible blob types. This is a helper definition for template functions. + */ +enum class ItemType : uint8_t { + U8 = NVS_TYPE_U8, + I8 = NVS_TYPE_I8, + U16 = NVS_TYPE_U16, + I16 = NVS_TYPE_I16, + U32 = NVS_TYPE_U32, + I32 = NVS_TYPE_I32, + U64 = NVS_TYPE_U64, + I64 = NVS_TYPE_I64, + SZ = NVS_TYPE_STR, + BLOB = 0x41, + BLOB_DATA = NVS_TYPE_BLOB, + BLOB_IDX = 0x48, + ANY = NVS_TYPE_ANY +}; + + +/** + * @brief A handle allowing nvs-entry related operations on the NVS. + * + * @note The scope of this handle may vary depending on the implementation, but normally would be the namespace of + * a particular partition. Outside that scope, nvs entries can't be accessed/altered. + */ +class NVSHandle { +public: + virtual ~NVSHandle() { } + + /** + * @brief set value for given key + * + * Sets value for key. Note that physical storage will not be updated until nvs_commit function is called. + * + * @param[in] key Key name. Maximal length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. + * @param[in] value The value to set. Allowed types are the ones declared in ItemType as well as enums. + * For strings, the maximum length (including null character) is + * 4000 bytes, if there is one complete page free for writing. + * This decreases, however, if the free space is fragmented. + * Note that enums loose their type information when stored in NVS. Ensure that the correct + * enum type is used during retrieval with \ref get_item! + * + * @return + * - ESP_OK if value was set successfully + * - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only + * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints + * - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the + * underlying storage to save the value + * - ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash + * write operation has failed. The value was written however, and + * update will be finished after re-initialization of nvs, provided that + * flash operation doesn't fail again. + * - ESP_ERR_NVS_VALUE_TOO_LONG if the string value is too long + */ + template + esp_err_t set_item(const char *key, T value); + virtual + esp_err_t set_string(const char *key, const char* value) = 0; + + /** + * @brief get value for given key + * + * These functions retrieve value for the key, given its name. If key does not + * exist, or the requested variable type doesn't match the type which was used + * when setting a value, an error is returned. + * + * In case of any error, out_value is not modified. + * + * @param[in] key Key name. Maximal length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. + * @param value The output value. All integral types which are declared in ItemType as well as enums + * are allowed. Note however that enums lost their type information when stored in NVS. + * Ensure that the correct enum type is used during retrieval with \ref get_item! + * + * @return + * - ESP_OK if the value was retrieved successfully + * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist + * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints + * - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data + */ + template + esp_err_t get_item(const char *key, T &value); + + /** + * @brief set variable length binary value for given key + * + * This family of functions set value for the key, given its name. Note that + * actual storage will not be updated until nvs_commit function is called. + * + * @param[in] key Key name. Maximal length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. + * @param[in] blob The blob value to set. + * @param[in] len length of binary value to set, in bytes; Maximum length is + * 508000 bytes or (97.6% of the partition size - 4000) bytes + * whichever is lower. + * + * @return + * - ESP_OK if value was set successfully + * - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only + * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints + * - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the + * underlying storage to save the value + * - ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash + * write operation has failed. The value was written however, and + * update will be finished after re-initialization of nvs, provided that + * flash operation doesn't fail again. + * - ESP_ERR_NVS_VALUE_TOO_LONG if the value is too long + * + * @note compare to \ref nvs_set_blob in nvs.h + */ + virtual esp_err_t set_blob(const char *key, const void* blob, size_t len) = 0; + + /** + * @brief get value for given key + * + * These functions retrieve the data of an entry, given its key. If key does not + * exist, or the requested variable type doesn't match the type which was used + * when setting a value, an error is returned. + * + * In case of any error, out_value is not modified. + * + * Both functions expect out_value to be a pointer to an already allocated variable + * of the given type. + * + * It is suggested that nvs_get/set_str is used for zero-terminated short C strings, and + * nvs_get/set_blob is used for arbitrary data structures and long C strings. + * + * @param[in] key Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. + * @param out_str/ Pointer to the output value. + * out_blob + * @param[inout] len The length of the output buffer pointed to by out_str/out_blob. + * Use \c get_item_size to query the size of the item beforehand. + * + * @return + * - ESP_OK if the value was retrieved successfully + * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist + * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints + * - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data + */ + virtual esp_err_t get_string(const char *key, char* out_str, size_t len) = 0; + virtual esp_err_t get_blob(const char *key, void* out_blob, size_t len) = 0; + + /** + * @brief Look up the size of an entry's data. + * + * @param[in] datatype Data type to search for. + * @param[in] key Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty. + * @param[out] size Size of the item, if it exists. + * For strings, this size includes the zero terminator. + * + * @return - ESP_OK if the item with specified type and key exists. Its size will be returned via \c size. + * - ESP_ERR_NVS_NOT_FOUND if an item with the requested key and type doesn't exist or any other + * error occurs. + */ + virtual esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) = 0; + + /** + * @brief Erases an entry. + */ + virtual esp_err_t erase_item(const char* key) = 0; + + /** + * Erases all entries in the scope of this handle. The scope may vary, depending on the implementation. + * + * @not If you want to erase the whole nvs flash (partition), refer to \ref + */ + virtual esp_err_t erase_all() = 0; + + /** + * Commits all changes done through this handle so far. + * Currently, NVS writes to storage right after the set and get functions, + * but this is not guaranteed. + */ + virtual esp_err_t commit() = 0; + + /** + * @brief Calculate all entries in the scope of the handle. + * + * @param[out] used_entries Returns amount of used entries from a namespace on success. + * + * + * @return + * - ESP_OK if the changes have been written successfully. + * Return param used_entries will be filled valid value. + * - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized. + * Return param used_entries will be filled 0. + * - ESP_ERR_INVALID_ARG if nvs_stats equal to NULL. + * - Other error codes from the underlying storage driver. + * Return param used_entries will be filled 0. + */ + virtual esp_err_t get_used_entry_count(size_t& usedEntries) = 0; + +protected: + virtual esp_err_t set_typed_item(ItemType datatype, const char *key, const void* data, size_t dataSize) = 0; + + virtual esp_err_t get_typed_item(ItemType datatype, const char *key, void* data, size_t dataSize) = 0; +}; + +/** + * @brief Opens non-volatile storage and returns a handle object. + * + * The handle is automatically closed on desctruction. The scope of the handle is the namespace ns_name + * in a particular partition partition_name. + * The parameters partition_name, ns_name and open_mode have the same meaning and restrictions as the parameters + * part_name, name and open_mode in \ref nvs_open_from_partition, respectively. + * + * @param err an optional pointer to an esp_err_t result of the open operation, having the same meaning as the return + * value in \ref nvs_open_from_partition: + * - ESP_OK if storage handle was opened successfully + * - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized + * - ESP_ERR_NVS_PART_NOT_FOUND if the partition with label "nvs" is not found + * - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and + * mode is NVS_READONLY + * - ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints + * - other error codes from the underlying storage driver + * + * @return shared pointer of an nvs handle on success, an empty shared pointer otherwise + */ +std::unique_ptr open_nvs_handle_from_partition(const char *partition_name, + const char *ns_name, + nvs_open_mode_t open_mode, + esp_err_t *err = nullptr); + +/** + * @brief This function does the same as \ref open_nvs_handle_from_partition but uses the default nvs partition + * instead of a partition_name parameter. + */ +std::unique_ptr open_nvs_handle(const char *ns_name, + nvs_open_mode_t open_mode, + esp_err_t *err = nullptr); + +// Helper functions for template usage +/** + * Help to translate all integral types into ItemType. + */ +template::value, void*>::type = nullptr> +constexpr ItemType itemTypeOf() +{ + return static_cast(((std::is_signed::value)?0x10:0x00) | sizeof(T)); +} + +/** + * Help to translate all enum types into integral ItemType. + */ +template::value, int>::type = 0> +constexpr ItemType itemTypeOf() +{ + return static_cast(((std::is_signed::value)?0x10:0x00) | sizeof(T)); +} + +template +constexpr ItemType itemTypeOf(const T&) +{ + return itemTypeOf(); +} + +// Template Implementations +template +esp_err_t NVSHandle::set_item(const char *key, T value) { + return set_typed_item(itemTypeOf(value), key, &value, sizeof(value)); +} + +template +esp_err_t NVSHandle::get_item(const char *key, T &value) { + return get_typed_item(itemTypeOf(value), key, &value, sizeof(value)); +} + +} // nvs + +#endif // NVS_HANDLE_HPP_ diff --git a/components/nvs_flash/test_nvs_host/crc.cpp b/components/nvs_flash/mock/int/crc.cpp similarity index 97% rename from components/nvs_flash/test_nvs_host/crc.cpp rename to components/nvs_flash/mock/int/crc.cpp index 4cbb9be9e..5c1b74564 100644 --- a/components/nvs_flash/test_nvs_host/crc.cpp +++ b/components/nvs_flash/mock/int/crc.cpp @@ -31,7 +31,7 @@ static const unsigned int crc32_le_table[256] = { 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, - + 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, @@ -52,7 +52,7 @@ static const unsigned int crc32_le_table[256] = { -extern "C" unsigned int crc32_le(unsigned int crc, unsigned char const * buf,unsigned int len) +extern "C" uint32_t esp_rom_crc32_le(unsigned int crc, unsigned char const * buf,unsigned int len) { unsigned int i; crc = ~crc; @@ -61,4 +61,3 @@ extern "C" unsigned int crc32_le(unsigned int crc, unsigned char const * buf,uns } return ~crc; } - diff --git a/components/nvs_flash/test_nvs_host/crc.h b/components/nvs_flash/mock/int/crc.h similarity index 72% rename from components/nvs_flash/test_nvs_host/crc.h rename to components/nvs_flash/mock/int/crc.h index c752b3030..f675da327 100644 --- a/components/nvs_flash/test_nvs_host/crc.h +++ b/components/nvs_flash/mock/int/crc.h @@ -20,7 +20,11 @@ extern "C" { #endif -uint32_t crc32_le(uint32_t crc, const uint8_t* buf, size_t len); +/** + * Mock function to replace ESP ROM function used in IDF with a Linux implementation. + * Note: the name MUST have the prefix esp_rom_* since tools/ci/check_rom_apis.sh checks and complains otherwise. + */ +uint32_t esp_rom_crc32_le(uint32_t crc, const uint8_t* buf, size_t len); #ifdef __cplusplus } diff --git a/components/nvs_flash/nvs_partition_generator/README.rst b/components/nvs_flash/nvs_partition_generator/README.rst index 11f0a2ea6..3a78a109d 100644 --- a/components/nvs_flash/nvs_partition_generator/README.rst +++ b/components/nvs_flash/nvs_partition_generator/README.rst @@ -1,76 +1,312 @@ NVS Partition Generator Utility =============================== +:link_to_translation:`zh_CN:[中文]` + Introduction ------------ -:component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` utility is designed to help create a binary file, compatible with NVS architecture defined in :doc:`Non-Volatile Storage `, based on user provided key-value pairs in a CSV file. -Utility is ideally suited for generating a binary blob, containing data specific to ODM/OEM, which can be flashed externally at the time of device manufacturing. This helps manufacturers set unique value for various parameters for each device, e.g. serial number, while using same application firmware for all devices. - -CSV file format ---------------- - -Each row of the .csv file should have 4 parameters, separated by comma. Below is the description of each of these parameters: +The utility :component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` creates a binary file based on key-value pairs provided in a CSV file. The binary file is compatible with NVS architecture defined in :doc:`Non-Volatile Storage `. +This utility is ideally suited for generating a binary blob, containing data specific to ODM/OEM, which can be flashed externally at the time of device manufacturing. This allows manufacturers to generate many instances of the same application firmware with customized parameters for each device, such as a serial number. -Key - Key of the data. Data can later be accessed from an application via this key. +Prerequisites +------------- +To use this utility in encryption mode, install the following packages: + - cryptography package -Type - Supported values are ``file``, ``data`` and ``namespace``. +All the required packages are included in `requirements.txt` in the root of the esp-idf directory. -Encoding - Supported values are: ``u8``, ``i8``, ``u16``, ``u32``, ``i32``, ``string``, ``hex2bin``, ``base64`` and ``binary``. This specifies how actual data values are encoded in the resultant binary file. Difference between ``string`` and ``binary`` encoding is that ``string`` data is terminated with a NULL character, whereas ``binary`` data is not. - - .. note:: For ``file`` type, only ``hex2bin``, ``base64``, ``string`` and ``binary`` is supported as of now. +CSV file format +--------------- -Value - Data value. +Each line of a .csv file should contain 4 parameters, separated by a comma. The table below provides the description for each of these parameters. -.. note:: Encoding and Value cells for ``namespace`` field type should be empty. Encoding and Value of ``namespace`` is fixed and isn't configurable. Any value in these cells are ignored. ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| No. | Parameter | Description | Notes | ++=====+===========+======================================================================+=====================================================+ +| 1 | Key | Key of the data. The data can be accessed later from | | +| | | an application using this key. | | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| 2 | Type | Supported values are ``file``, ``data`` and ``namespace``. | | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| 3 | Encoding | Supported values are: ``u8``, ``i8``, ``u16``, ``i16``, ``u32``, | As of now, for the ``file`` type, | +| | | ``i32``, ``u64``, ``i64``, ``string``, ``hex2bin``, ``base64`` | only ``hex2bin``, ``base64``, ``string``, | +| | | and ``binary``. | and ``binary`` encoding is supported. | +| | | This specifies how actual data values are encoded in the | | +| | | resulting binary file. The difference between the ``string`` | | +| | | and ``binary`` encoding is that ``string`` data is terminated | | +| | | with a NULL character, whereas ``binary`` data is not. | | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| 4 | Value | Data value. | Encoding and Value cells for the ``namespace`` | +| | | | field type should be empty. Encoding and Value | +| | | | of ``namespace`` is fixed and is not configurable. | +| | | | Any values in these cells are ignored. | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ -.. note:: First row of the CSV file should always be column header and isn't configurable. +.. note:: The first line of the CSV file should always be the column header and it is not configurable. -Below is an example dump of such CSV file:: +Below is an example dump of such a CSV file:: key,type,encoding,value <-- column header namespace_name,namespace,, <-- First entry should be of type "namespace" key1,data,u8,1 key2,file,string,/path/to/file -.. note:: Make sure there are no spaces before and after ',' in CSV file. +.. note:: + + Make sure there are **no spaces**: + - before and after ',' + - at the end of each line in a CSV file + NVS Entry and Namespace association ----------------------------------- -When a new namespace entry is encountered in the CSV file, each follow-up entries will be part of that namespace, until next namespace entry is found, in which case all the follow-up entries will be part of the new namespace. +When a namespace entry is encountered in a CSV file, each following entry will be treated as part of that namespace until the next namespace entry is found. At this point, all the following entries will be treated as part of the new namespace. + +.. note:: First entry in a CSV file should always be a ``namespace`` entry. + + +Multipage Blob Support +---------------------- + +By default, binary blobs are allowed to span over multiple pages and are written in the format mentioned in Section :ref:`structure_of_entry`. +If you intend to use an older format, the utility provides an option to disable this feature. + + +Encryption Support +------------------- -.. note:: First entry in a CSV file should always be ``namespace`` entry. +The NVS Partition Generator utility also allows you to create an encrypted binary file. The utility uses the AES-XTS encryption. Please refer to :ref:`nvs_encryption` for more details. + + +Decryption Support +------------------- +This utility allows you to decrypt an encrypted NVS binary file. The utility uses an NVS binary file encrypted using AES-XTS encryption. Please refer to :ref:`nvs_encryption` for more details. Running the utility ------------------- -python nvs_partition_gen.py [-h] [--input INPUT] [--output OUTPUT] [--size SIZE] +**Usage**:: + + python nvs_partition_gen.py [-h] {generate,generate-key,encrypt,decrypt} ... + + Optional Arguments: + +-----+------------+----------------------------------------------------------------------+ + | No. | Parameter | Description | + +=====+============+======================================================================+ + | 1 | -h, --help | show this help message and exit | + +-----+------------+----------------------------------------------------------------------+ + + Commands: + Run nvs_partition_gen.py {command} -h for additional help + +-----+--------------+--------------------------------------------------------------------+ + | No. | Parameter | Description | + +=====+==============+====================================================================+ + | 1 | generate | Generate NVS partition | + +-----+--------------+--------------------------------------------------------------------+ + | 2 | generate-key | Generate keys for encryption | + +-----+--------------+--------------------------------------------------------------------+ + | 3 | encrypt | Generate NVS encrypted partition | + +-----+--------------+--------------------------------------------------------------------+ + | 4 | decrypt | Decrypt NVS encrypted partition | + +-----+--------------+--------------------------------------------------------------------+ + + +To generate NVS partition (Default): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + **Usage**:: + + python nvs_partition_gen.py generate [-h] [--version {1,2}] [--outdir OUTDIR] + input output size + + Positional Arguments: + +--------------+----------------------------------------------------------------------+ + | Parameter | Description | + +==============+======================================================================+ + | input | Path to CSV file to parse | + +--------------+----------------------------------------------------------------------+ + | output | Path to output NVS binary file | + +--------------+----------------------------------------------------------------------+ + | size | Size of NVS partition in bytes (must be multiple of 4096) | + +--------------+----------------------------------------------------------------------+ -+------------------------+----------------------------------------------------------------------------------------------+ -| Arguments | Description | -+========================+==============================================================================================+ -| --input INPUT | Path to CSV file to parse. | -+------------------------+----------------------------------------------------------------------------------------------+ -| --output OUTPUT | Path to output generated binary file. | -+------------------------+----------------------------------------------------------------------------------------------+ -| --size SIZE | Size of NVS Partition in bytes (must be multiple of 4096) | -+------------------------+----------------------------------------------------------------------------------------------+ + Optional Arguments: + +-----------------+--------------------------------------------------------------------+ + | Parameter | Description | + +=================+====================================================================+ + | -h, --help | show this help message and exit | + +-----------------+--------------------------------------------------------------------+ + | --version {1,2} | Set multipage blob version. | + | | Version 1 - Multipage blob support disabled. | + | | Version 2 - Multipage blob support enabled. | + | | Default: Version 2 | + | | | + +-----------------+--------------------------------------------------------------------+ + | --outdir OUTDIR | Output directory to store files created | + | | (Default: current directory) | + +-----------------+--------------------------------------------------------------------+ + + +You can run the utility to generate NVS partition using the command below: A sample CSV file is provided with the utility:: - python nvs_partition_gen.py --input sample.csv --output sample.bin --size 0x3000 + python nvs_partition_gen.py generate sample_singlepage_blob.csv sample.bin 0x3000 + + +To generate only encryption keys: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + **Usage**:: + + python nvs_partition_gen.py generate-key [-h] [--keyfile KEYFILE] + [--outdir OUTDIR] + + Optional Arguments: + +--------------------+----------------------------------------------------------------------+ + | Parameter | Description | + +====================+======================================================================+ + | -h, --help | show this help message and exit | + +--------------------+----------------------------------------------------------------------+ + | --keyfile KEYFILE | Path to output encryption keys file | + +--------------------+----------------------------------------------------------------------+ + | --outdir OUTDIR | Output directory to store files created. | + | | (Default: current directory) | + +--------------------+----------------------------------------------------------------------+ + +You can run the utility to generate only encryption keys using the command below:: + + python nvs_partition_gen.py generate-key + + +To generate encrypted NVS partition: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + **Usage**:: + + python nvs_partition_gen.py encrypt [-h] [--version {1,2}] [--keygen] + [--keyfile KEYFILE] [--inputkey INPUTKEY] + [--outdir OUTDIR] + input output size + + Positional Arguments: + +--------------+----------------------------------------------------------------------+ + | Parameter | Description | + +==============+======================================================================+ + | input | Path to CSV file to parse | + +--------------+----------------------------------------------------------------------+ + | output | Path to output NVS binary file | + +--------------+----------------------------------------------------------------------+ + | size | Size of NVS partition in bytes (must be multiple of 4096) | + +--------------+----------------------------------------------------------------------+ + + + Optional Arguments: + +---------------------+--------------------------------------------------------------------+ + | Parameter | Description | + +=====================+====================================================================+ + | -h, --help | show this help message and exit | + | | | + +---------------------+--------------------------------------------------------------------+ + | --version {1,2} | Set multipage blob version. | + | | Version 1 - Multipage blob support disabled. | + | | Version 2 - Multipage blob support enabled. | + | | Default: Version 2 | + +---------------------+--------------------------------------------------------------------+ + | --keygen | Generates key for encrypting NVS partition | + +---------------------+--------------------------------------------------------------------+ + | --keyfile KEYFILE | Path to output encryption keys file | + +---------------------+--------------------------------------------------------------------+ + | --inputkey INPUTKEY | File having key for encrypting NVS partition | + +---------------------+--------------------------------------------------------------------+ + | --outdir OUTDIR | Output directory to store files created | + | | (Default: current directory) | + +---------------------+--------------------------------------------------------------------+ + + +You can run the utility to encrypt NVS partition using the command below: +A sample CSV file is provided with the utility: + +- Encrypt by allowing the utility to generate encryption keys:: + + python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --keygen + +.. note:: Encryption key of the following format ``/keys/keys-.bin`` is created. + +- Encrypt by allowing the utility to generate encryption keys and store it in provided custom filename:: + + python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --keygen --keyfile sample_keys.bin + +.. note:: Encryption key of the following format ``/keys/sample_keys.bin`` is created. +.. note:: This newly created file having encryption keys in ``keys/`` directory is compatible with NVS key-partition structure. Refer to :ref:`nvs_key_partition` for more details. + +- Encrypt by providing the encryption keys as input binary file:: + + python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --inputkey sample_keys.bin + +To decrypt encrypted NVS partition: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + **Usage**:: + + python nvs_partition_gen.py decrypt [-h] [--outdir OUTDIR] input key output + + Positional Arguments: + +--------------+----------------------------------------------------------------------+ + | Parameter | Description | + +==============+======================================================================+ + | input | Path to encrypted NVS partition file to parse | + +--------------+----------------------------------------------------------------------+ + | key | Path to file having keys for decryption | + +--------------+----------------------------------------------------------------------+ + | output | Path to output decrypted binary file | + +--------------+----------------------------------------------------------------------+ + + + Optional Arguments: + +---------------------+--------------------------------------------------------------------+ + | Parameter | Description | + +=====================+====================================================================+ + | -h, --help | show this help message and exit | + +---------------------+--------------------------------------------------------------------+ + | --outdir OUTDIR | Output directory to store files created | + | | (Default: current directory) | + +---------------------+--------------------------------------------------------------------+ + + +You can run the utility to decrypt encrypted NVS partition using the command below:: + + python nvs_partition_gen.py decrypt sample_encr.bin sample_keys.bin sample_decr.bin + +You can also provide the format version number: + - Multipage Blob Support Disabled (Version 1) + - Multipage Blob Support Enabled (Version 2) + + +Multipage Blob Support Disabled (Version 1): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can run the utility in this format by setting the version parameter to 1, as shown below. +A sample CSV file is provided with the utility:: + + python nvs_partition_gen.py generate sample_singlepage_blob.csv sample.bin 0x3000 --version 1 + + +Multipage Blob Support Enabled (Version 2): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can run the utility in this format by setting the version parameter to 2, as shown below. +A sample CSV file is provided with the utility:: + + python nvs_partition_gen.py generate sample_multipage_blob.csv sample.bin 0x4000 --version 2 + .. note:: *Minimum NVS Partition Size needed is 0x3000 bytes.* .. note:: *When flashing the binary onto the device, make sure it is consistent with the application's sdkconfig.* + Caveats ------- -- Utility doesn't check for duplicate keys and will write data pertaining to both keys. User needs to make sure keys are distinct. -- Once a new page is created, no data will be written in the space left in previous page. Fields in the CSV file need to be ordered in such a way so as to optimize memory. +- Utility does not check for duplicate keys and will write data pertaining to both keys. You need to make sure that the keys are distinct. +- Once a new page is created, no data will be written in the space left on the previous page. Fields in the CSV file need to be ordered in such a way as to optimize memory. - 64-bit datatype is not yet supported. + diff --git a/components/nvs_flash/nvs_partition_generator/README_CN.rst b/components/nvs_flash/nvs_partition_generator/README_CN.rst new file mode 100644 index 000000000..24094e993 --- /dev/null +++ b/components/nvs_flash/nvs_partition_generator/README_CN.rst @@ -0,0 +1,304 @@ +NVS 分区生æˆç¨‹åº +=============================== + +:link_to_translation:`en:[English]` + +ä»‹ç» +------------ + +NVS 分区生æˆç¨‹åº (:component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py`) æ ¹æ® CSV 文件中的键值对生æˆäºŒè¿›åˆ¶æ–‡ä»¶ã€‚该二进制文件与 :doc:`éžæ˜“失性存储器 (NVS) ` 中定义的 NVS 结构兼容。NVS 分区生æˆç¨‹åºé€‚åˆç”¨äºŽç”ŸæˆäºŒè¿›åˆ¶æ•°æ®ï¼ˆBlob),其中包括设备生产时å¯ä»Žå¤–部烧录的 ODM/OEM æ•°æ®ã€‚这也使得生产制造商在使用åŒä¸€ä¸ªå›ºä»¶çš„åŸºç¡€ä¸Šï¼Œé€šè¿‡è‡ªå®šä¹‰å‚æ•°ï¼Œå¦‚åºåˆ—å·ç­‰ï¼Œä¸ºæ¯ä¸ªè®¾å¤‡ç”Ÿæˆä¸åŒé…置。 + +准备工作 +------------- + +在加密模å¼ä¸‹ä½¿ç”¨è¯¥ç¨‹åºï¼Œéœ€å®‰è£…下列软件包: + - cryptography package + +根目录下的 `requirements.txt` 包å«å¿…需 python 包,请预先安装。 + + +CSV æ–‡ä»¶æ ¼å¼ +--------------- + +.csv 文件æ¯è¡Œéœ€åŒ…å«å››ä¸ªå‚数,以逗å·éš”å¼€ã€‚å…·ä½“å‚æ•°æè¿°è§ä¸‹è¡¨ï¼š + ++------+----------+--------------------------------------------------------------+-----------------------------------------------------------------+ +| åºå· | 傿•° | æè¿° | 说明 | ++======+==========+==============================================================+=================================================================+ +| 1 | Key | 主键,应用程åºå¯é€šè¿‡æŸ¥è¯¢æ­¤é”®æ¥èŽ·å–æ•°æ®ã€‚ | | ++------+----------+--------------------------------------------------------------+-----------------------------------------------------------------+ +| 2 | Type | æ”¯æŒ ``file``ã€``data`` å’Œ ``namespace``。 | | ++------+----------+--------------------------------------------------------------+-----------------------------------------------------------------+ +| 3 | Encoding | æ”¯æŒ ``u8``ã€``i8``ã€``u16``ã€``u32``〠| ``file`` | +| | | ``i32``ã€``string``ã€``hex2bin``ã€``base64`` å’Œ ``binary``。 | 类型当å‰ä»…æ”¯æŒ | +| | | 决定二进制 ``bin`` 文件中 value è¢«ç¼–ç æˆçš„类型。 | ``hex2bin``ã€``base64``〠| +| | | ``string`` å’Œ ``binary`` ç¼–ç çš„区别在于, | ``string`` å’Œ ``binary`` ç¼–ç ã€‚ | +| | | ``string`` æ•°æ®ä»¥ NULL 字符结尾,``binary`` æ•°æ®åˆ™ä¸æ˜¯ã€‚ | | ++------+----------+--------------------------------------------------------------+-----------------------------------------------------------------+ +| 4 | Value | Data value | ``namespace`` 字段的 ``encoding`` å’Œ ``value`` 应为空。 | +| | | | ``namespace`` çš„ ``encoding`` å’Œ ``value`` 为固定值,ä¸å¯è®¾ç½®ã€‚ | +| | | | 这些å•元格中的所有值都会被忽视。 | ++------+----------+--------------------------------------------------------------+-----------------------------------------------------------------+ + +.. note:: CSV 文件的第一行应为列标题,ä¸å¯è®¾ç½®ã€‚ + +此类 CSV 文件的 Dump 示例如下:: + + key,type,encoding,value <-- 列标题 + namespace_name,namespace,, <-- 第一个æ¡ç›®ä¸º "namespace" + key1,data,u8,1 + key2,file,string,/path/to/file + + +.. note:: + + 请确ä¿ï¼š + - é€—å· ',' å‰åŽæ— ç©ºæ ¼ï¼› + - CSV 文件æ¯è¡Œæœ«å°¾æ— ç©ºæ ¼ã€‚ + +NVS æ¡ç›®å’Œå‘½å空间 (namespace) +----------------------------------- + +如 CSV 文件中出现命å空间æ¡ç›®ï¼ŒåŽç»­æ¡ç›®å‡ä¼šè¢«è§†ä¸ºè¯¥å‘½å空间的一部分,直至找到下一个命å空间æ¡ç›®ã€‚找到新命å空间æ¡ç›®åŽï¼ŒåŽç»­æ‰€æœ‰æ¡ç›®éƒ½ä¼šè¢«è§†ä¸ºæ–°å‘½å空间的一部分。 + +.. note:: CSV 文件中第一个æ¡ç›®åº”始终为 ``namespace``。 + + +支æŒå¤šé¡µ Blob +---------------------- + +默认情况下,二进制 Blob å¯è·¨å¤šé¡µï¼Œæ ¼å¼å‚考 :ref:`structure_of_entry` 章节。如需使用旧版格å¼ï¼Œå¯åœ¨ç¨‹åºä¸­ç¦ç”¨è¯¥åŠŸèƒ½ã€‚ + + +支æŒåР坆 +------------------- + +NVS 分区生æˆç¨‹åºè¿˜å¯ä½¿ç”¨ AES-XTS 加密生æˆäºŒè¿›åˆ¶åŠ å¯†æ–‡ä»¶ã€‚æ›´å¤šä¿¡æ¯è¯¦è§ :ref:`nvs_encryption`。 + +支æŒè§£å¯† +------------------- +如果 NVS 二进制文件采用了 AES-XTS 加密,该程åºè¿˜å¯å¯¹æ­¤ç±»æ–‡ä»¶è¿›è¡Œè§£å¯†ï¼Œæ›´å¤šä¿¡æ¯è¯¦è§ :ref:`nvs_encryption`。 + +è¿è¡Œç¨‹åº +------------------- + +**使用方法**:: + + python nvs_partition_gen.py [-h] {generate,generate-key,encrypt,decrypt} ... + +**å¯é€‰å‚æ•°**: + ++------+------------+----------------------+ +| åºå· | 傿•° | æè¿° | ++------+------------+----------------------+ +| 1 | -h, --help | 显示帮助信æ¯å¹¶é€€å‡º | ++------+------------+----------------------+ + +**命令**:: + + è¿è¡Œ nvs_partition_gen.py {command} -h æŸ¥çœ‹æ›´å¤šå¸®åŠ©ä¿¡æ¯ + ++------+--------------+---------------+ +| åºå· | 傿•° | æè¿° | ++------+--------------+---------------+ +| 1 | generate | ç”Ÿæˆ NVS 分区 | ++------+--------------+---------------+ +| 2 | generate-key | 生æˆåР坆坆钥 | ++------+--------------+---------------+ +| 3 | encrypt | 加密 NVS 分区 | ++------+--------------+---------------+ +| 4 | decrypt | 解密 NVS 分区 | ++------+--------------+---------------+ + + +ç”Ÿæˆ NVS 分区(默认模å¼ï¼‰ +---------------------------------- + +**使用方法**:: + + python nvs_partition_gen.py generate [-h] [--version {1,2}] [--outdir OUTDIR] + input output size + +**ä½ç½®å‚æ•°**: + ++--------+--------------------------------------------------+ +| 傿•° | æè¿° | ++--------+--------------------------------------------------+ +| input | å¾…è§£æžçš„ CSV 文件路径 | ++--------+--------------------------------------------------+ +| output | NVS 二进制文件的输出路径 | ++--------+--------------------------------------------------+ +| size | NVS 分区大å°ï¼ˆä»¥å­—节为å•ä½ï¼Œä¸”为 4096 的整数å€ï¼‰ | ++--------+--------------------------------------------------+ + +**å¯é€‰å‚æ•°**: + ++-----------------+------------------------------------------------+ +| 傿•° | æè¿° | ++-----------------+------------------------------------------------+ +| -h, --help | 显示帮助信æ¯å¹¶é€€å‡º | ++-----------------+------------------------------------------------+ +| --version {1,2} | - 设置多页 Blob 版本。 | +| | - 版本 1:ç¦ç”¨å¤šé¡µ Blobï¼› | +| | - 版本 2:å¯ç”¨å¤šé¡µ Blobï¼› | +| | - 默认版本:版本 2。 | ++-----------------+------------------------------------------------+ +| --outdir OUTDIR | 输出目录,用于存储创建的文件。(默认当å‰ç›®å½•) | ++-----------------+------------------------------------------------+ + +è¿è¡Œå¦‚下命令创建 NVS 分区,该程åºåŒæ—¶ä¼šæä¾› CSV 示例文件:: + + python nvs_partition_gen.py generate sample_singlepage_blob.csv sample.bin 0x3000 + +仅生æˆåР坆坆钥 +----------------------- + +**使用方法**:: + + python nvs_partition_gen.py generate-key [-h] [--keyfile KEYFILE] + [--outdir OUTDIR] + +**å¯é€‰å‚æ•°**: + ++-------------------+------------------------------------------------+ +| 傿•° | æè¿° | ++-------------------+------------------------------------------------+ +| -h, --help | 显示帮助信æ¯å¹¶é€€å‡º | ++-------------------+------------------------------------------------+ +| --keyfile KEYFILE | 加密密钥文件的输出路径 | ++-------------------+------------------------------------------------+ +| --outdir OUTDIR | 输出目录,用于存储创建的文件。(默认当å‰ç›®å½•) | ++-------------------+------------------------------------------------+ + +è¿è¡Œä»¥ä¸‹å‘½ä»¤ä»…生æˆåР坆坆钥:: + + python nvs_partition_gen.py generate-key + +ç”Ÿæˆ NVS 加密分区 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**使用方法**:: + + python nvs_partition_gen.py encrypt [-h] [--version {1,2}] [--keygen] + [--keyfile KEYFILE] [--inputkey INPUTKEY] + [--outdir OUTDIR] + input output size + +**ä½ç½®å‚æ•°**: + ++--------+--------------------------------------+ +| 傿•° | æè¿° | ++--------+--------------------------------------+ +| input | å¾…è§£æž CSV 文件的路径 | ++--------+--------------------------------------+ +| output | NVS 二进制文件的输出路径 | ++--------+--------------------------------------+ +| size | NVS åˆ†åŒºå¤§å° | +| | (以字节为å•ä½ï¼Œä¸”为 4096 的整数å€ï¼‰ | ++--------+--------------------------------------+ + +**å¯é€‰å‚æ•°**: + ++---------------------+------------------------------+ +| 傿•° | æè¿° | ++---------------------+------------------------------+ +| -h, --help | 显示帮助信æ¯å¹¶é€€å‡º | ++---------------------+------------------------------+ +| --version {1,2} | - 设置多页 Blob 版本。 | +| | - 版本 1:ç¦ç”¨å¤šé¡µ Blobï¼› | +| | - 版本 2:å¯ç”¨å¤šé¡µ Blobï¼› | +| | - 默认版本:版本 2。 | ++---------------------+------------------------------+ +| --keygen | ç”Ÿæˆ NVS 分区加密密钥 | ++---------------------+------------------------------+ +| --keyfile KEYFILE | 密钥文件的输出路径 | ++---------------------+------------------------------+ +| --inputkey INPUTKEY | å†…å« NVS 分区加密密钥的文件 | ++---------------------+------------------------------+ +| --outdir OUTDIR | 输出目录,用于存储创建的文件 | +| | (默认当å‰ç›®å½•) | ++---------------------+------------------------------+ + +è¿è¡Œä»¥ä¸‹å‘½ä»¤åР坆 NVS 分区,该程åºåŒæ—¶ä¼šæä¾›ä¸€ä¸ª CSV 示例文件。 + +- 通过 NVS 分区生æˆç¨‹åºç”ŸæˆåР坆坆钥æ¥åР坆:: + + python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --keygen + +.. note:: 创建的加密密钥格å¼ä¸º ``/keys/keys-.bin``。 + +- 通过 NVS 分区生æˆç¨‹åºç”ŸæˆåŠ å¯†å¯†é’¥ï¼Œå¹¶å°†å¯†é’¥å­˜å‚¨äºŽè‡ªå®šä¹‰çš„æ–‡ä»¶ä¸­:: + + python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --keygen --keyfile sample_keys.bin + +.. note:: 创建的加密密钥格å¼ä¸º ``/keys/keys-.bin``。 +.. note:: 加密密钥存储于新建文件的 ``keys/`` 目录下,与 NVS 密钥分区结构兼容。更多信æ¯è¯·å‚考 :ref:`nvs_key_partition`。 + +- 将加密密钥用作二进制输入文件æ¥è¿›è¡ŒåР坆:: + + python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --inputkey sample_keys.bin + +解密 NVS 分区 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**使用方法**:: + + python nvs_partition_gen.py decrypt [-h] [--outdir OUTDIR] input key output + +**ä½ç½®å‚æ•°**: + ++--------+-------------------------------+ +| 傿•° | æè¿° | ++--------+-------------------------------+ +| input | å¾…è§£æžçš„ NVS 加密分区文件路径 | ++--------+-------------------------------+ +| key | 嫿œ‰è§£å¯†å¯†é’¥çš„æ–‡ä»¶è·¯å¾„ | ++--------+-------------------------------+ +| output | 已解密的二进制文件输出路径 | ++--------+-------------------------------+ + +**å¯é€‰å‚æ•°**: + ++-----------------+------------------------------+ +| 傿•° | æè¿° | ++-----------------+------------------------------+ +| -h, --help | 显示帮助信æ¯å¹¶é€€å‡º | ++-----------------+------------------------------+ +| --outdir OUTDIR | 输出目录,用于存储创建的文件 | +| | (默认当å‰ç›®å½•) | ++-----------------+------------------------------+ + +è¿è¡Œä»¥ä¸‹å‘½ä»¤è§£å¯†å·²åŠ å¯†çš„ NVS 分区:: + + python nvs_partition_gen.py decrypt sample_encr.bin sample_keys.bin sample_decr.bin + +您å¯ä»¥è‡ªå®šä¹‰æ ¼å¼ç‰ˆæœ¬å·ï¼š + +- 版本 1:ç¦ç”¨å¤šé¡µ Blob +- 版本 2:å¯ç”¨å¤šé¡µ Blob + +版本 1:ç¦ç”¨å¤šé¡µ Blob +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +如需ç¦ç”¨å¤šé¡µ Blobï¼Œè¯·æŒ‰ç…§å¦‚ä¸‹å‘½ä»¤å°†ç‰ˆæœ¬å‚æ•°è®¾ç½®ä¸º 1,以此格å¼è¿è¡Œåˆ†åŒºç”Ÿæˆç¨‹åºã€‚该程åºåŒæ—¶ä¼šæä¾›ä¸€ä¸ª CSV 示例文件:: + + python nvs_partition_gen.py generate sample_singlepage_blob.csv sample.bin 0x3000 --version 1 + +版本 2:å¯ç”¨å¤šé¡µ Blob +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +如需å¯ç”¨å¤šé¡µ Blobï¼Œè¯·æŒ‰ç…§å¦‚ä¸‹å‘½ä»¤å°†ç‰ˆæœ¬å‚æ•°è®¾ç½®ä¸º 2,以此格å¼è¿è¡Œåˆ†åŒºç”Ÿæˆç¨‹åºã€‚该程åºåŒæ—¶ä¼šæä¾›ä¸€ä¸ª CSV 示例文件:: + + python nvs_partition_gen.py generate sample_multipage_blob.csv sample.bin 0x4000 --version 2 + +.. note:: NVS 分区最å°ä¸º 0x3000 字节。 + +.. note:: 将二进制文件烧录至设备时,请确ä¿ä¸Žåº”用的 sdkconfig 设置一致。 + + +说明 +------- + +- 分区生æˆç¨‹åºä¸ä¼šå¯¹é‡å¤é”®è¿›è¡Œæ£€æŸ¥ï¼Œè€Œå°†æ•°æ®åŒæ—¶å†™å…¥è¿™ä¸¤ä¸ªé‡å¤é”®ä¸­ã€‚请注æ„ä¸è¦ä½¿ç”¨åŒå的键; +- 新页é¢åˆ›å»ºåŽï¼Œå‰ä¸€é¡µçš„空白处ä¸ä¼šå†å†™å…¥æ•°æ®ã€‚CSV æ–‡ä»¶ä¸­çš„å­—æ®µé¡»æŒ‰æ¬¡åºæŽ’åˆ—ä»¥ä¼˜åŒ–å†…å­˜ï¼› +- æš‚ä¸æ”¯æŒ 64 使•°æ®ç±»åž‹ã€‚ diff --git a/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py b/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py index d5ddc55b0..890f5222b 100755 --- a/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py +++ b/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py @@ -19,32 +19,55 @@ # from __future__ import division, print_function -from builtins import int, range, bytes -from io import open -import sys + import argparse +import array import binascii +import codecs +import datetime +import distutils.dir_util +import os import random import struct -import os -import array -import csv +import sys import zlib -import codecs -from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes -from cryptography.hazmat.backends import default_backend +from builtins import bytes, int, range +from io import open + +from future.moves.itertools import zip_longest -VERSION1_PRINT = "v1 - Multipage Blob Support Disabled" -VERSION2_PRINT = "v2 - Multipage Blob Support Enabled" +try: + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +except ImportError: + print('The cryptography package is not installed.' + 'Please refer to the Get Started section of the ESP-IDF Programming Guide for ' + 'setting up the required packages.') + raise + +VERSION1_PRINT = 'V1 - Multipage Blob Support Disabled' +VERSION2_PRINT = 'V2 - Multipage Blob Support Enabled' + + +def reverse_hexbytes(addr_tmp): + addr = [] + reversed_bytes = '' + for i in range(0, len(addr_tmp), 2): + addr.append(addr_tmp[i:i + 2]) + reversed_bytes = ''.join(reversed(addr)) + + return reversed_bytes """ Class for standard NVS page structure """ + + class Page(object): PAGE_PARAMS = { - "max_size": 4096, - "max_old_blob_size": 1984, - "max_new_blob_size": 4000, - "max_entries": 126 + 'max_size': 4096, + 'max_old_blob_size': 1984, + 'max_new_blob_size': 4000, + 'max_entries': 126 } # Item type codes @@ -54,6 +77,8 @@ class Page(object): I16 = 0x12 U32 = 0x04 I32 = 0x14 + U64 = 0x08 + I64 = 0x18 SZ = 0x21 BLOB = 0x41 BLOB_DATA = 0x42 @@ -68,25 +93,21 @@ class Page(object): CHUNK_ANY = 0xFF ACTIVE = 0xFFFFFFFE FULL = 0xFFFFFFFC - VERSION1=0xFF - VERSION2=0xFE + VERSION1 = 0xFF + VERSION2 = 0xFE - def __init__(self, page_num, is_rsrv_page=False): + def __init__(self, page_num, version, is_rsrv_page=False): self.entry_num = 0 - self.is_encrypt = False - self.encr_key = None self.bitmap_array = array.array('B') - self.version = Page.VERSION2 - self.page_buf = bytearray(b'\xff')*Page.PAGE_PARAMS["max_size"] + self.version = version + self.page_buf = bytearray(b'\xff') * Page.PAGE_PARAMS['max_size'] if not is_rsrv_page: self.bitmap_array = self.create_bitmap_array() - self.set_header(page_num) - - def set_header(self, page_num): - global page_header + self.set_header(page_num, version) + def set_header(self, page_num, version): # set page state to active - page_header= bytearray(b'\xff') *32 + page_header = bytearray(b'\xff') * 32 page_state_active_seq = Page.ACTIVE struct.pack_into(' 2: if not addr_len % 2: addr_tmp = addr - tweak_tmp = self.reverse_hexbytes(addr_tmp) - tweak_val = tweak_tmp + (init_tweak_val * (tweak_len_needed - (len(tweak_tmp)))) else: addr_tmp = init_tweak_val + addr - tweak_tmp = self.reverse_hexbytes(addr_tmp) - tweak_val = tweak_tmp + (init_tweak_val * (tweak_len_needed - (len(tweak_tmp)))) + tweak_tmp = reverse_hexbytes(addr_tmp) + tweak_val = tweak_tmp + (init_tweak_val * (tweak_len_needed - (len(tweak_tmp)))) else: tweak_val = addr + (init_tweak_val * (tweak_len_needed - len(addr))) @@ -207,11 +212,10 @@ def encrypt_data(self, data_input, no_of_entries, nvs_obj): return encr_data_to_write - def write_entry_to_buf(self, data, entrycount,nvs_obj): encr_data = bytearray() - if self.is_encrypt: + if nvs_obj.encrypt: encr_data_ret = self.encrypt_data(data, entrycount,nvs_obj) encr_data[0:len(encr_data_ret)] = encr_data_ret data = encr_data @@ -226,7 +230,6 @@ def write_entry_to_buf(self, data, entrycount,nvs_obj): self.write_bitmaparray() self.entry_num += 1 - def set_crc_header(self, entry_struct): crc_data = bytearray(b'28') crc_data[0:4] = entry_struct[0:4] @@ -236,7 +239,6 @@ def set_crc_header(self, entry_struct): struct.pack_into('=0, "Page overflow!!" + tailroom = (Page.PAGE_PARAMS['max_entries'] - self.entry_num - 1) * Page.SINGLE_ENTRY_SIZE + assert tailroom >= 0, 'Page overflow!!' # Split the binary data into two and store a chunk of available size onto curr page if tailroom < remaining_size: @@ -266,7 +268,7 @@ def write_varlen_binary_data(self, entry_struct, ns_index, key, data, data_size, # Calculate no. of entries data chunk will require datachunk_rounded_size = (chunk_size + 31) & ~31 datachunk_entry_count = datachunk_rounded_size // 32 - datachunk_total_entry_count = datachunk_entry_count + 1 # +1 for the entry header + datachunk_total_entry_count = datachunk_entry_count + 1 # +1 for the entry header # Set Span entry_struct[2] = datachunk_total_entry_count @@ -276,7 +278,7 @@ def write_varlen_binary_data(self, entry_struct, ns_index, key, data, data_size, entry_struct[3] = chunk_index # Set data chunk - data_chunk = data[offset:offset + chunk_size] + data_chunk = data[offset:offset + chunk_size] # Compute CRC of data chunk struct.pack_into(' Page.PAGE_PARAMS["max_old_blob_size"]: - raise InputError("Version %s\n%s: Size exceeds max allowed length." % (VERSION1_PRINT,key)) - - if version == Page.VERSION2: - if encoding == "string": - if datalen > Page.PAGE_PARAMS["max_new_blob_size"]: - raise InputError("Version %s\n%s: Size exceeds max allowed length." % (VERSION2_PRINT,key)) + if datalen > Page.PAGE_PARAMS['max_old_blob_size']: + if self.version == Page.VERSION1: + raise InputError(' Input File: Size (%d) exceeds max allowed length `%s` bytes for key `%s`.' + % (datalen, Page.PAGE_PARAMS['max_old_blob_size'], key)) + else: + if encoding == 'string': + raise InputError(' Input File: Size (%d) exceeds max allowed length `%s` bytes for key `%s`.' + % (datalen, Page.PAGE_PARAMS['max_old_blob_size'], key)) # Calculate no. of entries data will require rounded_size = (datalen + 31) & ~31 data_entry_count = rounded_size // 32 - total_entry_count = data_entry_count + 1 # +1 for the entry header + total_entry_count = data_entry_count + 1 # +1 for the entry header # Check if page is already full and new page is needed to be created right away - if version == Page.VERSION1: - if encoding in ["string", "hex2bin", "binary", "base64"]: - if (self.entry_num + total_entry_count) >= Page.PAGE_PARAMS["max_entries"]: - raise PageFullError() - else: - if encoding == "string": - if (self.entry_num + total_entry_count) >= Page.PAGE_PARAMS["max_entries"]: - raise PageFullError() + if self.entry_num >= Page.PAGE_PARAMS['max_entries']: + raise PageFullError() + elif (self.entry_num + total_entry_count) >= Page.PAGE_PARAMS['max_entries']: + if not (self.version == Page.VERSION2 and encoding in ['hex2bin', 'binary', 'base64']): + raise PageFullError() # Entry header - entry_struct = bytearray(b'\xff')*32 + entry_struct = bytearray(b'\xff') * 32 # Set Namespace Index entry_struct[0] = ns_index # Set Span - if version == Page.VERSION2: - if encoding == "string": + if self.version == Page.VERSION2: + if encoding == 'string': entry_struct[2] = data_entry_count + 1 # Set Chunk Index chunk_index = Page.CHUNK_ANY @@ -408,51 +401,58 @@ def write_varlen_data(self, key, data, encoding, ns_index,nvs_obj): entry_struct[8:8 + len(key)] = key.encode() # set Type - if encoding == "string": + if encoding == 'string': entry_struct[1] = Page.SZ - elif encoding in ["hex2bin", "binary", "base64"]: + elif encoding in ['hex2bin', 'binary', 'base64']: entry_struct[1] = Page.BLOB - if version == Page.VERSION2 and (encoding in ["hex2bin", "binary", "base64"]): - entry_struct = self.write_varlen_binary_data(entry_struct,ns_index,key,data,\ - datalen,total_entry_count, encoding, nvs_obj) + if self.version == Page.VERSION2 and (encoding in ['hex2bin', 'binary', 'base64']): + entry_struct = self.write_varlen_binary_data(entry_struct,ns_index,key,data, + datalen,total_entry_count, encoding, nvs_obj) else: self.write_single_page_entry(entry_struct, data, datalen, data_entry_count, nvs_obj) - - """ Low-level function to write data of primitive type into page buffer. """ def write_primitive_data(self, key, data, encoding, ns_index,nvs_obj): # Check if entry exceeds max number of entries allowed per page - if self.entry_num >= Page.PAGE_PARAMS["max_entries"]: + if self.entry_num >= Page.PAGE_PARAMS['max_entries']: raise PageFullError() - entry_struct = bytearray(b'\xff')*32 - entry_struct[0] = ns_index # namespace index - entry_struct[2] = 0x01 # Span + entry_struct = bytearray(b'\xff') * 32 + entry_struct[0] = ns_index # namespace index + entry_struct[2] = 0x01 # Span chunk_index = Page.CHUNK_ANY entry_struct[3] = chunk_index # write key - key_array = b'\x00' *16 + key_array = b'\x00' * 16 entry_struct[8:24] = key_array entry_struct[8:8 + len(key)] = key.encode() - if encoding == "u8": + if encoding == 'u8': entry_struct[1] = Page.U8 struct.pack_into('/ + :param outdir: Target output dir to store files + :param filepath: Path of target file + ''' + bin_ext = '.bin' + # Expand if tilde(~) provided in path + outdir = os.path.expanduser(outdir) + + if filepath: + key_file_name, ext = os.path.splitext(filepath) + if not ext: + filepath = key_file_name + bin_ext + elif bin_ext not in ext: + sys.exit('Error: `%s`. Only `%s` extension allowed.' % (filepath, bin_ext)) + + # Create dir if does not exist + if not (os.path.isdir(outdir)): + distutils.dir_util.mkpath(outdir) + + filedir, filename = os.path.split(filepath) + filedir = os.path.join(outdir,filedir,'') + if filedir and not os.path.isdir(filedir): + distutils.dir_util.mkpath(filedir) + + if os.path.isabs(filepath): + if not outdir == os.getcwd(): + print('\nWarning: `%s` \n\t==> absolute path given so outdir is ignored for this file.' % filepath) + # Set to empty as outdir is ignored here + outdir = '' + + # Set full path - outdir + filename + filepath = os.path.join(outdir, '') + filepath + + return outdir, filepath + + +def encrypt(args): + ''' + Generate encrypted NVS Partition + :param args: Command line arguments given + ''' + key = None + bin_ext = '.bin' + + check_size(args.size) + if (args.keygen is False) and (not args.inputkey): + sys.exit('Error. --keygen or --inputkey argument needed.') + elif args.keygen and args.inputkey: + sys.exit('Error. --keygen and --inputkey both are not allowed.') + elif not args.keygen and args.keyfile: + print('\nWarning:','--inputkey argument is given. --keyfile argument will be ignored...') + + if args.inputkey: + # Check if key file has .bin extension + filename, ext = os.path.splitext(args.inputkey) + if bin_ext not in ext: + sys.exit('Error: `%s`. Only `%s` extension allowed.' % (args.inputkey, bin_ext)) + key = bytearray() + with open(args.inputkey, 'rb') as key_f: + key = key_f.read(64) + + # Generate encrypted NVS Partition + generate(args, is_encr_enabled=True, encr_key=key) + + +def decrypt_data(data_input, decr_key, page_num, entry_no, entry_size): + ''' + Decrypt NVS data entry + ''' + page_max_size = 4096 + first_entry_offset = 64 + init_tweak_val = '0' + tweak_len_needed = 32 # in hex + tweak_tmp = '' + + data_input = binascii.hexlify(data_input) + rel_addr = page_num * page_max_size + first_entry_offset + + # Set tweak value + offset = entry_no * entry_size + addr = hex(rel_addr + offset)[2:] + addr_len = len(addr) + if addr_len > 2: + if not addr_len % 2: + addr_tmp = addr + else: + addr_tmp = init_tweak_val + addr + tweak_tmp = reverse_hexbytes(addr_tmp) + tweak_val = tweak_tmp + (init_tweak_val * (tweak_len_needed - (len(tweak_tmp)))) + else: + tweak_val = addr + (init_tweak_val * (tweak_len_needed - len(addr))) + + if type(data_input) == bytes: + data_input = data_input.decode() + + # Decrypt 32 bytes of data using AES-XTS decryption + backend = default_backend() + plain_text = codecs.decode(data_input, 'hex') + tweak = codecs.decode(tweak_val, 'hex') + cipher = Cipher(algorithms.AES(decr_key), modes.XTS(tweak), backend=backend) + decryptor = cipher.decryptor() + decrypted_data = decryptor.update(plain_text) + + return decrypted_data + + +def decrypt(args): + ''' + Decrypt encrypted NVS Partition + :param args: Command line arguments given + ''' + bin_ext = '.bin' + nvs_read_bytes = 32 + decrypted_entry_no = 0 + file_entry_no = 0 + page_num = 0 + page_max_size = 4096 + start_entry_offset = 0 + empty_data_entry = bytearray(b'\xff') * nvs_read_bytes + + # Check if key file has .bin extension + input_files = [args.input, args.key, args.output] + for filepath in input_files: + filename, ext = os.path.splitext(filepath) + if bin_ext not in ext: + sys.exit('Error: `%s`. Only `%s` extension allowed.' % (filepath, bin_ext)) + with open(args.key,'rb') as decr_key_file: + decr_key = decr_key_file.read(64) + + args.outdir, args.output = set_target_filepath(args.outdir, args.output) + + output_buf = bytearray(b'\xff') + + with open(args.input, 'rb') as input_file, open(args.output,'wb') as output_file: + while True: + if file_entry_no == 128: + decrypted_entry_no = 0 + file_entry_no = 0 + page_num += 1 + data_entry = input_file.read(nvs_read_bytes) + if not data_entry: + break + if data_entry != empty_data_entry and file_entry_no not in [0,1]: + data_entry = decrypt_data(data_entry, decr_key, page_num, decrypted_entry_no, nvs_read_bytes) + decrypted_entry_no += 1 + write_entry_no = ((page_num * page_max_size) + file_entry_no) + start_idx = start_entry_offset + (write_entry_no * nvs_read_bytes) + end_idx = nvs_read_bytes + output_buf[start_idx:end_idx] = data_entry + file_entry_no += 1 + start_entry_offset += nvs_read_bytes + output_file.write(output_buf) + + print('\nCreated NVS decrypted binary: ===>', args.output) + + +def generate_key(args): + ''' + Generate encryption keys + :param args: Command line arguments given + ''' + page_max_size = 4096 + keys_dir = 'keys' + output_keyfile = None + bin_ext = '.bin' + + if not args.keyfile: + timestamp = datetime.datetime.now().strftime('%m-%d_%H-%M') + args.keyfile = 'keys-' + timestamp + bin_ext + + keys_outdir = os.path.join(args.outdir,keys_dir, '') + # Create keys/ dir in if does not exist + if not (os.path.isdir(keys_outdir)): + distutils.dir_util.mkpath(keys_outdir) + keys_outdir, output_keyfile = set_target_filepath(keys_outdir, args.keyfile) + + key = ''.join(random.choice('0123456789abcdef') for _ in range(128)).strip() + encr_key_bytes = codecs.decode(key, 'hex') + key_len = len(encr_key_bytes) + + keys_buf = bytearray(b'\xff') * page_max_size + keys_buf[0:key_len] = encr_key_bytes + crc_data = keys_buf[0:key_len] + crc_data = bytes(crc_data) + crc = zlib.crc32(crc_data, 0xFFFFFFFF) + struct.pack_into(' ', output_keyfile) + + return key + + +def generate(args, is_encr_enabled=False, encr_key=None): + ''' + Generate NVS Partition + :param args: Command line arguments given + :param is_encr_enabled: Encryption enabled/disabled + :param encr_key: Key to encrypt NVS partition + ''' + is_dir_new = False + bin_ext = '.bin' + + input_size = check_size(args.size) + if args.version == 1: + args.version = Page.VERSION1 + elif args.version == 2: + args.version = Page.VERSION2 + + # Check if key file has .bin extension + filename, ext = os.path.splitext(args.output) + if bin_ext not in ext: + sys.exit('Error: `%s`. Only `.bin` extension allowed.' % args.output) + args.outdir, args.output = set_target_filepath(args.outdir, args.output) + + if is_encr_enabled and not encr_key: + encr_key = generate_key(args) + + input_file = open(args.input, 'rt', encoding='utf8') + output_file = open(args.output, 'wb') + + with open(args.input, 'rt', encoding='utf8') as input_file,\ + open(args.output, 'wb') as output_file,\ + nvs_open(output_file, input_size, args.version, is_encrypt=is_encr_enabled, key=encr_key) as nvs_obj: + + if nvs_obj.version == Page.VERSION1: + version_set = VERSION1_PRINT + else: + version_set = VERSION2_PRINT -def nvs_part_gen(input_filename=None, output_filename=None, input_part_size=None, is_key_gen=None, encrypt_mode=None, key_file=None, version_no=None): - """ Wrapper to generate nvs partition binary + print('\nCreating NVS binary with version:', version_set) - :param input_filename: Name of input file containing data - :param output_filename: Name of output file to store generated binary - :param input_part_size: Size of partition in bytes (must be multiple of 4096) - :param is_key_gen: Enable encryption key generation in encryption mode - :param encrypt_mode: Enable/Disable encryption mode - :param key_file: Input file having encryption keys in encryption mode - :param version_no: Format Version number - :return: None - """ + line = input_file.readline().strip() - global key_input, key_len_needed + # Comments are skipped + while line.startswith('#'): + line = input_file.readline().strip() + if not isinstance(line, str): + line = line.encode('utf-8') - key_len_needed = 64 - key_input = bytearray() + header = line.split(',') - if key_gen: - key_input = ''.join(random.choice('0123456789abcdef') for _ in range(128)).strip() - elif key_file: - with open(key_file, 'rb') as key_f: - key_input = key_f.read(64) + while True: + line = input_file.readline().strip() + if not isinstance(line, str): + line = line.encode('utf-8') - if all(arg is not None for arg in [input_filename, output_filename, input_size]): - input_file = open(input_filename, 'rt', encoding='utf8') - output_file = open(output_filename, 'wb') + value = line.split(',') + if len(value) == 1 and '' in value: + break - with nvs_open(output_file, input_size) as nvs_obj: - reader = csv.DictReader(input_file, delimiter=',') - for row in reader: - try: - write_entry(nvs_obj, row["key"], row["type"], row["encoding"], row["value"]) - except (InputError) as e: - print(e) - input_file.close() - output_file.close() - sys.exit(-2) - - input_file.close() - output_file.close() - - - if key_gen: - keys_page_buf = bytearray(b'\xff')*Page.PAGE_PARAMS["max_size"] - key_bytes = bytearray() - if len(key_input) == key_len_needed: - key_bytes = key_input - else: - key_bytes = codecs.decode(key_input, 'hex') - key_len = len(key_bytes) - keys_page_buf[0:key_len] = key_bytes - crc_data = keys_page_buf[0:key_len] - crc_data = bytes(crc_data) - crc = zlib.crc32(crc_data, 0xFFFFFFFF) - struct.pack_into(' 15: + raise InputError('Length of key `{}` should be <= 15 characters.'.format(data['key'])) + write_entry(nvs_obj, data['key'], data['type'], data['encoding'], data['value']) + except InputError as e: + print(e) + filedir, filename = os.path.split(args.output) + if filename: + print('\nWarning: NVS binary not created...') + os.remove(args.output) + if is_dir_new and not filedir == os.getcwd(): + print('\nWarning: Output dir not created...') + os.rmdir(filedir) + sys.exit(-2) + + print('\nCreated NVS binary: ===>', args.output) def main(): - parser = argparse.ArgumentParser(description="ESP32 NVS partition generation utility") - nvs_part_gen_group = parser.add_argument_group('To generate NVS partition') - nvs_part_gen_group.add_argument( - "--input", - help="Path to CSV file to parse.", - default=None) - - nvs_part_gen_group.add_argument( - "--output", - help='Path to output converted binary file.', - default=None) - - nvs_part_gen_group.add_argument( - "--size", - help='Size of NVS Partition in bytes (must be multiple of 4096)') - + parser = argparse.ArgumentParser(description='\nESP NVS partition generation utility', formatter_class=argparse.RawTextHelpFormatter) + subparser = parser.add_subparsers(title='Commands', + dest='command', + help='\nRun nvs_partition_gen.py {command} -h for additional help\n\n') + + parser_gen = subparser.add_parser('generate', + help='Generate NVS partition', + formatter_class=argparse.RawTextHelpFormatter) + parser_gen.set_defaults(func=generate) + parser_gen.add_argument('input', + default=None, + help='Path to CSV file to parse') + parser_gen.add_argument('output', + default=None, + help='Path to output NVS binary file') + parser_gen.add_argument('size', + default=None, + help='Size of NVS partition in bytes\ + \n(must be multiple of 4096)') + parser_gen.add_argument('--version', + choices=[1,2], + default=2, + type=int, + help='''Set multipage blob version.\ + \nVersion 1 - Multipage blob support disabled.\ + \nVersion 2 - Multipage blob support enabled.\ + \nDefault: Version 2''') + parser_gen.add_argument('--outdir', + default=os.getcwd(), + help='Output directory to store files created\ + \n(Default: current directory)') + parser_gen_key = subparser.add_parser('generate-key', + help='Generate keys for encryption', + formatter_class=argparse.RawTextHelpFormatter) + parser_gen_key.set_defaults(func=generate_key) + parser_gen_key.add_argument('--keyfile', + default=None, + help='Path to output encryption keys file') + parser_gen_key.add_argument('--outdir', + default=os.getcwd(), + help='Output directory to store files created.\ + \n(Default: current directory)') + parser_encr = subparser.add_parser('encrypt', + help='Generate NVS encrypted partition', + formatter_class=argparse.RawTextHelpFormatter) + parser_encr.set_defaults(func=encrypt) + parser_encr.add_argument('input', + default=None, + help='Path to CSV file to parse') + parser_encr.add_argument('output', + default=None, + help='Path to output NVS binary file') + parser_encr.add_argument('size', + default=None, + help='Size of NVS partition in bytes\ + \n(must be multiple of 4096)') + parser_encr.add_argument('--version', + choices=[1,2], + default=2, + type=int, + help='''Set multipage blob version.\ + \nVersion 1 - Multipage blob support disabled.\ + \nVersion 2 - Multipage blob support enabled.\ + \nDefault: Version 2''') + parser_encr.add_argument('--keygen', + action='store_true', + default=False, + help='Generates key for encrypting NVS partition') + parser_encr.add_argument('--keyfile', + default=None, + help='Path to output encryption keys file') + parser_encr.add_argument('--inputkey', + default=None, + help='File having key for encrypting NVS partition') + parser_encr.add_argument('--outdir', + default=os.getcwd(), + help='Output directory to store files created.\ + \n(Default: current directory)') + parser_decr = subparser.add_parser('decrypt', + help='Decrypt NVS encrypted partition', + formatter_class=argparse.RawTextHelpFormatter) + parser_decr.set_defaults(func=decrypt) + parser_decr.add_argument('input', + default=None, + help='Path to encrypted NVS partition file to parse') + parser_decr.add_argument('key', + default=None, + help='Path to file having keys for decryption') + parser_decr.add_argument('output', + default=None, + help='Path to output decrypted binary file') + parser_decr.add_argument('--outdir', + default=os.getcwd(), + help='Output directory to store files created.\ + \n(Default: current directory)') args = parser.parse_args() - input_filename = args.input - output_filename = args.output - part_size = args.size - version_no = 'v1' - is_key_gen = 'false' - is_encrypt_data = 'false' - key_file = None - - print_arg_str = "Invalid.\nTo generate nvs partition binary --input, --output and --size arguments are mandatory." - - check_input_args(input_filename,output_filename, part_size, is_key_gen, is_encrypt_data, key_file, version_no, print_arg_str) - nvs_part_gen(input_filename, output_filename, part_size, is_key_gen, is_encrypt_data, key_file, version_no) + args.func(args) -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/components/nvs_flash/nvs_partition_generator/sample_multipage_blob.csv b/components/nvs_flash/nvs_partition_generator/sample_multipage_blob.csv index 384ac6919..e9546cb41 100644 --- a/components/nvs_flash/nvs_partition_generator/sample_multipage_blob.csv +++ b/components/nvs_flash/nvs_partition_generator/sample_multipage_blob.csv @@ -1,3 +1,4 @@ +# Sample csv file key,type,encoding,value dummyNamespace,namespace,, dummyU8Key,data,u8,127 diff --git a/components/nvs_flash/nvs_partition_generator/sample_singlepage_blob.csv b/components/nvs_flash/nvs_partition_generator/sample_singlepage_blob.csv index c99f513cf..10d3cc635 100644 --- a/components/nvs_flash/nvs_partition_generator/sample_singlepage_blob.csv +++ b/components/nvs_flash/nvs_partition_generator/sample_singlepage_blob.csv @@ -1,3 +1,4 @@ +# Sample csv file key,type,encoding,value dummyNamespace,namespace,, dummyU8Key,data,u8,127 diff --git a/components/nvs_flash/src/compressed_enum_table.hpp b/components/nvs_flash/src/compressed_enum_table.hpp index 319d86a45..dcf9d0999 100644 --- a/components/nvs_flash/src/compressed_enum_table.hpp +++ b/components/nvs_flash/src/compressed_enum_table.hpp @@ -35,7 +35,7 @@ class CompressedEnumTable Tenum get(size_t index) const { - assert(index >= 0 && index < Nitems); + assert(index < Nitems); size_t wordIndex = index / ITEMS_PER_WORD; size_t offset = (index % ITEMS_PER_WORD) * Nbits; @@ -44,7 +44,7 @@ class CompressedEnumTable void set(size_t index, Tenum val) { - assert(index >= 0 && index < Nitems); + assert(index < Nitems); size_t wordIndex = index / ITEMS_PER_WORD; size_t offset = (index % ITEMS_PER_WORD) * Nbits; diff --git a/components/nvs_flash/src/intrusive_list.h b/components/nvs_flash/src/intrusive_list.h index fc92442cd..bb580502e 100644 --- a/components/nvs_flash/src/intrusive_list.h +++ b/components/nvs_flash/src/intrusive_list.h @@ -15,6 +15,7 @@ #define intrusive_list_h #include +#include template class intrusive_list; @@ -229,8 +230,7 @@ class intrusive_list { return mSize == 0; } - - + void clear() { while (mFirst) { @@ -238,6 +238,16 @@ class intrusive_list } } + void clearAndFreeNodes() + { + while (mFirst) { + auto tmp = mFirst; + erase(mFirst); + delete tmp; + } + } + + protected: T* mFirst = nullptr; T* mLast = nullptr; diff --git a/components/nvs_flash/src/nvs_api.cpp b/components/nvs_flash/src/nvs_api.cpp index 15f76d1dd..fe58ccd2c 100644 --- a/components/nvs_flash/src/nvs_api.cpp +++ b/components/nvs_flash/src/nvs_api.cpp @@ -11,64 +11,64 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#include "sdkconfig.h" #include "nvs.hpp" #include "nvs_flash.h" #include "nvs_storage.hpp" #include "intrusive_list.h" #include "nvs_platform.hpp" +#include "nvs_partition_manager.hpp" #include "esp_partition.h" -#include "sdkconfig.h" +#include +#include "nvs_handle_simple.hpp" +#include "esp_err.h" + +#ifdef LINUX_TARGET +#include "crc.h" +#define ESP_LOGD(...) +#else // LINUX_TARGET +#include -#ifdef ESP_PLATFORM // Uncomment this line to force output from this module // #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG #include "esp_log.h" static const char* TAG = "nvs"; -#else -#define ESP_LOGD(...) -#endif +#endif // ! LINUX_TARGET -class HandleEntry : public intrusive_list_node -{ - static uint32_t s_nvs_next_handle; +class NVSHandleEntry : public intrusive_list_node { public: - HandleEntry() {} + NVSHandleEntry(nvs::NVSHandleSimple *handle, const char* part_name) + : nvs_handle(handle), + mHandle(++s_nvs_next_handle), + handle_part_name(part_name) { } - HandleEntry(bool readOnly, uint8_t nsIndex, nvs::Storage* StoragePtr) : - mHandle(++s_nvs_next_handle), // Begin the handle value with 1 - mReadOnly(readOnly), - mNsIndex(nsIndex), - mStoragePtr(StoragePtr) - { + ~NVSHandleEntry() { + delete nvs_handle; } - nvs_handle mHandle; - uint8_t mReadOnly; - uint8_t mNsIndex; - nvs::Storage* mStoragePtr; + nvs::NVSHandleSimple *nvs_handle; + nvs_handle_t mHandle; + const char* handle_part_name; +private: + static uint32_t s_nvs_next_handle; }; -#ifdef ESP_PLATFORM -SemaphoreHandle_t nvs::Lock::mSemaphore = NULL; -#endif +uint32_t NVSHandleEntry::s_nvs_next_handle; + +extern "C" void nvs_dump(const char *partName); + +#ifndef LINUX_TARGET +SemaphoreHandle_t nvs::Lock::mSemaphore = nullptr; +#endif // ! LINUX_TARGET using namespace std; using namespace nvs; -static intrusive_list s_nvs_handles; -uint32_t HandleEntry::s_nvs_next_handle; -static intrusive_list s_nvs_storage_list; +static intrusive_list s_nvs_handles; static nvs::Storage* lookup_storage_from_name(const char *name) { - auto it = find_if(begin(s_nvs_storage_list), end(s_nvs_storage_list), [=](Storage& e) -> bool { - return (strcmp(e.getPartName(), name) == 0); - }); - - if (it == end(s_nvs_storage_list)) { - return NULL; - } - return it; + return NVSPartitionManager::get_instance()->lookup_storage_from_name(name); } extern "C" void nvs_dump(const char *partName) @@ -77,359 +77,415 @@ extern "C" void nvs_dump(const char *partName) nvs::Storage* pStorage; pStorage = lookup_storage_from_name(partName); - if (pStorage == NULL) { + if (pStorage == nullptr) { return; } pStorage->debugDump(); - return; } -extern "C" esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount) +static esp_err_t close_handles_and_deinit(const char* part_name) { - ESP_LOGD(TAG, "nvs_flash_init_custom partition=%s start=%d count=%d", partName, baseSector, sectorCount); - nvs::Storage* new_storage = NULL; - nvs::Storage* storage = lookup_storage_from_name(partName); - if (storage == NULL) { - new_storage = new nvs::Storage((const char *)partName); - storage = new_storage; - } + auto belongs_to_part = [=](NVSHandleEntry& e) -> bool { + return strncmp(e.nvs_handle->get_partition_name(), part_name, NVS_PART_NAME_MAX_SIZE) == 0; + }; - esp_err_t err = storage->init(baseSector, sectorCount); - if (new_storage != NULL) { - if (err == ESP_OK) { - s_nvs_storage_list.push_back(new_storage); - } else { - delete new_storage; - } + auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), belongs_to_part); + + while (it != end(s_nvs_handles)) { + s_nvs_handles.erase(it); + it = find_if(begin(s_nvs_handles), end(s_nvs_handles), belongs_to_part); } - return err; + + // Deinit partition + return NVSPartitionManager::get_instance()->deinit_partition(part_name); } -#ifdef ESP_PLATFORM -extern "C" esp_err_t nvs_flash_init_partition(const char *part_name) +extern "C" esp_err_t nvs_flash_init_partition_ptr(const esp_partition_t *partition) { Lock::init(); Lock lock; - nvs::Storage* mStorage; - mStorage = lookup_storage_from_name(part_name); - if (mStorage) { - return ESP_OK; + if (partition == nullptr) { + return ESP_ERR_INVALID_ARG; } - const esp_partition_t* partition = esp_partition_find_first( - ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name); - if (partition == NULL) { - return ESP_ERR_NOT_FOUND; + NVSPartition *part = new (std::nothrow) NVSPartition(partition); + if (part == nullptr) { + return ESP_ERR_NO_MEM; } - return nvs_flash_init_custom(part_name, partition->address / SPI_FLASH_SEC_SIZE, + esp_err_t init_res = NVSPartitionManager::get_instance()->init_custom(part, + partition->address / SPI_FLASH_SEC_SIZE, partition->size / SPI_FLASH_SEC_SIZE); -} -extern "C" esp_err_t nvs_flash_init(void) -{ - return nvs_flash_init_partition(NVS_DEFAULT_PART_NAME); + if (init_res != ESP_OK) { + delete part; + } + + return init_res; } -extern "C" esp_err_t nvs_flash_deinit_partition(const char* partition_name) +#ifndef LINUX_TARGET +extern "C" esp_err_t nvs_flash_init_partition(const char *part_name) { Lock::init(); Lock lock; - nvs::Storage* storage = lookup_storage_from_name(partition_name); - if (!storage) { - return ESP_ERR_NVS_NOT_INITIALIZED; + return NVSPartitionManager::get_instance()->init_partition(part_name); +} + +extern "C" esp_err_t nvs_flash_init(void) +{ +#ifdef CONFIG_NVS_ENCRYPTION + esp_err_t ret = ESP_FAIL; + const esp_partition_t *key_part = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL); + if (key_part == NULL) { + ESP_LOGE(TAG, "CONFIG_NVS_ENCRYPTION is enabled, but no partition with subtype nvs_keys found in the partition table."); + return ret; } - /* Clean up handles related to the storage being deinitialized */ - auto it = s_nvs_handles.begin(); - auto next = it; - while(it != s_nvs_handles.end()) { - next++; - if (it->mStoragePtr == storage) { - ESP_LOGD(TAG, "Deleting handle %d (ns=%d) related to partition \"%s\" (missing call to nvs_close?)", - it->mHandle, it->mNsIndex, partition_name); - s_nvs_handles.erase(it); - delete static_cast(it); + nvs_sec_cfg_t cfg = {}; + ret = nvs_flash_read_security_cfg(key_part, &cfg); + if (ret == ESP_ERR_NVS_KEYS_NOT_INITIALIZED) { + ESP_LOGI(TAG, "NVS key partition empty, generating keys"); + ret = nvs_flash_generate_keys(key_part, &cfg); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to generate keys: [0x%02X] (%s)", ret, esp_err_to_name(ret)); + return ret; } - it = next; + } else if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to read NVS security cfg: [0x%02X] (%s)", ret, esp_err_to_name(ret)); + return ret; } - /* Finally delete the storage itself */ - s_nvs_storage_list.erase(storage); - delete storage; + ret = nvs_flash_secure_init_partition(NVS_DEFAULT_PART_NAME, &cfg); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_LOGE(TAG, "Failed to initialize NVS partition: [0x%02X] (%s)", ret, esp_err_to_name(ret)); + return ret; + } + ESP_LOGI(TAG, "NVS partition \"%s\" is encrypted.", NVS_DEFAULT_PART_NAME); + return ret; +#else // CONFIG_NVS_ENCRYPTION + return nvs_flash_init_partition(NVS_DEFAULT_PART_NAME); +#endif +} - return ESP_OK; +#ifdef CONFIG_NVS_ENCRYPTION +extern "C" esp_err_t nvs_flash_secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg) +{ + Lock::init(); + Lock lock; + + return NVSPartitionManager::get_instance()->secure_init_partition(part_name, cfg); } -extern "C" esp_err_t nvs_flash_deinit(void) +extern "C" esp_err_t nvs_flash_secure_init(nvs_sec_cfg_t* cfg) { - return nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME); + return nvs_flash_secure_init_partition(NVS_DEFAULT_PART_NAME, cfg); } +#endif extern "C" esp_err_t nvs_flash_erase_partition(const char *part_name) { + Lock::init(); + Lock lock; + + // if the partition is initialized, uninitialize it first + if (NVSPartitionManager::get_instance()->lookup_storage_from_name(part_name)) { + esp_err_t err = close_handles_and_deinit(part_name); + + // only hypothetical/future case, deinit_partition() only fails if partition is uninitialized + if (err != ESP_OK) { + return err; + } + } + const esp_partition_t* partition = esp_partition_find_first( ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name); - if (partition == NULL) { + if (partition == nullptr) { return ESP_ERR_NOT_FOUND; } return esp_partition_erase_range(partition, 0, partition->size); } -extern "C" esp_err_t nvs_flash_erase() +extern "C" esp_err_t nvs_flash_erase_partition_ptr(const esp_partition_t *partition) +{ + Lock::init(); + Lock lock; + + if (partition == nullptr) { + return ESP_ERR_INVALID_ARG; + } + + // if the partition is initialized, uninitialize it first + if (NVSPartitionManager::get_instance()->lookup_storage_from_name(partition->label)) { + const esp_err_t err = close_handles_and_deinit(partition->label); + + // only hypothetical/future case, deinit_partition() only fails if partition is uninitialized + if (err != ESP_OK) { + return err; + } + } + + return esp_partition_erase_range(partition, 0, partition->size); +} + +extern "C" esp_err_t nvs_flash_erase(void) { return nvs_flash_erase_partition(NVS_DEFAULT_PART_NAME); } -#endif +#endif // ! LINUX_TARGET -static esp_err_t nvs_find_ns_handle(nvs_handle handle, HandleEntry& entry) +extern "C" esp_err_t nvs_flash_deinit_partition(const char* partition_name) { - auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool { - return e.mHandle == handle; + Lock::init(); + Lock lock; + + return close_handles_and_deinit(partition_name); +} + +extern "C" esp_err_t nvs_flash_deinit(void) +{ + return nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME); +} + +static esp_err_t nvs_find_ns_handle(nvs_handle_t c_handle, NVSHandleSimple** handle) +{ + auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](NVSHandleEntry& e) -> bool { + return e.mHandle == c_handle; }); if (it == end(s_nvs_handles)) { return ESP_ERR_NVS_INVALID_HANDLE; } - entry = *it; + *handle = it->nvs_handle; return ESP_OK; } -extern "C" esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode open_mode, nvs_handle *out_handle) +extern "C" esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle) { Lock lock; ESP_LOGD(TAG, "%s %s %d", __func__, name, open_mode); - uint8_t nsIndex; - nvs::Storage* sHandle; - - sHandle = lookup_storage_from_name(part_name); - if (sHandle == NULL) { - return ESP_ERR_NVS_PART_NOT_FOUND; - } - esp_err_t err = sHandle->createOrOpenNamespace(name, open_mode == NVS_READWRITE, nsIndex); - if (err != ESP_OK) { - return err; + NVSHandleSimple *handle; + esp_err_t result = NVSPartitionManager::get_instance()->open_handle(part_name, name, open_mode, &handle); + if (result == ESP_OK) { + NVSHandleEntry *entry = new (std::nothrow) NVSHandleEntry(handle, part_name); + if (entry) { + s_nvs_handles.push_back(entry); + *out_handle = entry->mHandle; + } else { + delete handle; + return ESP_ERR_NO_MEM; + } } - HandleEntry *handle_entry = new HandleEntry(open_mode==NVS_READONLY, nsIndex, sHandle); - s_nvs_handles.push_back(handle_entry); - - *out_handle = handle_entry->mHandle; - - return ESP_OK; + return result; } -extern "C" esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle) +extern "C" esp_err_t nvs_open(const char* name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle) { - if (s_nvs_storage_list.size() == 0) { - return ESP_ERR_NVS_NOT_INITIALIZED; - } - return nvs_open_from_partition(NVS_DEFAULT_PART_NAME, name, open_mode, out_handle); } -extern "C" void nvs_close(nvs_handle handle) +extern "C" void nvs_close(nvs_handle_t handle) { Lock lock; ESP_LOGD(TAG, "%s %d", __func__, handle); - auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool { + auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](NVSHandleEntry& e) -> bool { return e.mHandle == handle; }); if (it == end(s_nvs_handles)) { return; } s_nvs_handles.erase(it); - delete static_cast(it); + delete static_cast(it); } -extern "C" esp_err_t nvs_erase_key(nvs_handle handle, const char* key) +extern "C" esp_err_t nvs_erase_key(nvs_handle_t c_handle, const char* key) { Lock lock; ESP_LOGD(TAG, "%s %s\r\n", __func__, key); - HandleEntry entry; - auto err = nvs_find_ns_handle(handle, entry); + NVSHandleSimple *handle; + auto err = nvs_find_ns_handle(c_handle, &handle); if (err != ESP_OK) { return err; } - if (entry.mReadOnly) { - return ESP_ERR_NVS_READ_ONLY; - } - return entry.mStoragePtr->eraseItem(entry.mNsIndex, key); + + return handle->erase_item(key); } -extern "C" esp_err_t nvs_erase_all(nvs_handle handle) +extern "C" esp_err_t nvs_erase_all(nvs_handle_t c_handle) { Lock lock; ESP_LOGD(TAG, "%s\r\n", __func__); - HandleEntry entry; - auto err = nvs_find_ns_handle(handle, entry); + NVSHandleSimple *handle; + auto err = nvs_find_ns_handle(c_handle, &handle); if (err != ESP_OK) { return err; } - if (entry.mReadOnly) { - return ESP_ERR_NVS_READ_ONLY; - } - return entry.mStoragePtr->eraseNamespace(entry.mNsIndex); + + return handle->erase_all(); } template -static esp_err_t nvs_set(nvs_handle handle, const char* key, T value) +static esp_err_t nvs_set(nvs_handle_t c_handle, const char* key, T value) { Lock lock; ESP_LOGD(TAG, "%s %s %d %d", __func__, key, sizeof(T), (uint32_t) value); - HandleEntry entry; - auto err = nvs_find_ns_handle(handle, entry); + NVSHandleSimple *handle; + auto err = nvs_find_ns_handle(c_handle, &handle); if (err != ESP_OK) { return err; } - if (entry.mReadOnly) { - return ESP_ERR_NVS_READ_ONLY; - } - return entry.mStoragePtr->writeItem(entry.mNsIndex, key, value); + + return handle->set_item(key, value); } -extern "C" esp_err_t nvs_set_i8 (nvs_handle handle, const char* key, int8_t value) +extern "C" esp_err_t nvs_set_i8 (nvs_handle_t handle, const char* key, int8_t value) { return nvs_set(handle, key, value); } -extern "C" esp_err_t nvs_set_u8 (nvs_handle handle, const char* key, uint8_t value) +extern "C" esp_err_t nvs_set_u8 (nvs_handle_t handle, const char* key, uint8_t value) { return nvs_set(handle, key, value); } -extern "C" esp_err_t nvs_set_i16 (nvs_handle handle, const char* key, int16_t value) +extern "C" esp_err_t nvs_set_i16 (nvs_handle_t handle, const char* key, int16_t value) { return nvs_set(handle, key, value); } -extern "C" esp_err_t nvs_set_u16 (nvs_handle handle, const char* key, uint16_t value) +extern "C" esp_err_t nvs_set_u16 (nvs_handle_t handle, const char* key, uint16_t value) { return nvs_set(handle, key, value); } -extern "C" esp_err_t nvs_set_i32 (nvs_handle handle, const char* key, int32_t value) +extern "C" esp_err_t nvs_set_i32 (nvs_handle_t handle, const char* key, int32_t value) { return nvs_set(handle, key, value); } -extern "C" esp_err_t nvs_set_u32 (nvs_handle handle, const char* key, uint32_t value) +extern "C" esp_err_t nvs_set_u32 (nvs_handle_t handle, const char* key, uint32_t value) { return nvs_set(handle, key, value); } -extern "C" esp_err_t nvs_set_i64 (nvs_handle handle, const char* key, int64_t value) +extern "C" esp_err_t nvs_set_i64 (nvs_handle_t handle, const char* key, int64_t value) { return nvs_set(handle, key, value); } -extern "C" esp_err_t nvs_set_u64 (nvs_handle handle, const char* key, uint64_t value) +extern "C" esp_err_t nvs_set_u64 (nvs_handle_t handle, const char* key, uint64_t value) { return nvs_set(handle, key, value); } -extern "C" esp_err_t nvs_commit(nvs_handle handle) +extern "C" esp_err_t nvs_commit(nvs_handle_t c_handle) { Lock lock; // no-op for now, to be used when intermediate cache is added - HandleEntry entry; - return nvs_find_ns_handle(handle, entry); + NVSHandleSimple *handle; + auto err = nvs_find_ns_handle(c_handle, &handle); + if (err != ESP_OK) { + return err; + } + return handle->commit(); } -extern "C" esp_err_t nvs_set_str(nvs_handle handle, const char* key, const char* value) +extern "C" esp_err_t nvs_set_str(nvs_handle_t c_handle, const char* key, const char* value) { Lock lock; ESP_LOGD(TAG, "%s %s %s", __func__, key, value); - HandleEntry entry; - auto err = nvs_find_ns_handle(handle, entry); + NVSHandleSimple *handle; + auto err = nvs_find_ns_handle(c_handle, &handle); if (err != ESP_OK) { return err; } - return entry.mStoragePtr->writeItem(entry.mNsIndex, nvs::ItemType::SZ, key, value, strlen(value) + 1); + return handle->set_string(key, value); } -extern "C" esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length) +extern "C" esp_err_t nvs_set_blob(nvs_handle_t c_handle, const char* key, const void* value, size_t length) { Lock lock; ESP_LOGD(TAG, "%s %s %d", __func__, key, length); - HandleEntry entry; - auto err = nvs_find_ns_handle(handle, entry); + NVSHandleSimple *handle; + auto err = nvs_find_ns_handle(c_handle, &handle); if (err != ESP_OK) { return err; } - return entry.mStoragePtr->writeItem(entry.mNsIndex, nvs::ItemType::BLOB, key, value, length); + return handle->set_blob(key, value, length); } template -static esp_err_t nvs_get(nvs_handle handle, const char* key, T* out_value) +static esp_err_t nvs_get(nvs_handle_t c_handle, const char* key, T* out_value) { Lock lock; ESP_LOGD(TAG, "%s %s %d", __func__, key, sizeof(T)); - HandleEntry entry; - auto err = nvs_find_ns_handle(handle, entry); + NVSHandleSimple *handle; + auto err = nvs_find_ns_handle(c_handle, &handle); if (err != ESP_OK) { return err; } - return entry.mStoragePtr->readItem(entry.mNsIndex, key, *out_value); + return handle->get_item(key, *out_value); } -extern "C" esp_err_t nvs_get_i8 (nvs_handle handle, const char* key, int8_t* out_value) +extern "C" esp_err_t nvs_get_i8 (nvs_handle_t c_handle, const char* key, int8_t* out_value) { - return nvs_get(handle, key, out_value); + return nvs_get(c_handle, key, out_value); } -extern "C" esp_err_t nvs_get_u8 (nvs_handle handle, const char* key, uint8_t* out_value) +extern "C" esp_err_t nvs_get_u8 (nvs_handle_t c_handle, const char* key, uint8_t* out_value) { - return nvs_get(handle, key, out_value); + return nvs_get(c_handle, key, out_value); } -extern "C" esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value) +extern "C" esp_err_t nvs_get_i16 (nvs_handle_t c_handle, const char* key, int16_t* out_value) { - return nvs_get(handle, key, out_value); + return nvs_get(c_handle, key, out_value); } -extern "C" esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value) +extern "C" esp_err_t nvs_get_u16 (nvs_handle_t c_handle, const char* key, uint16_t* out_value) { - return nvs_get(handle, key, out_value); + return nvs_get(c_handle, key, out_value); } -extern "C" esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value) +extern "C" esp_err_t nvs_get_i32 (nvs_handle_t c_handle, const char* key, int32_t* out_value) { - return nvs_get(handle, key, out_value); + return nvs_get(c_handle, key, out_value); } -extern "C" esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value) +extern "C" esp_err_t nvs_get_u32 (nvs_handle_t c_handle, const char* key, uint32_t* out_value) { - return nvs_get(handle, key, out_value); + return nvs_get(c_handle, key, out_value); } -extern "C" esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value) +extern "C" esp_err_t nvs_get_i64 (nvs_handle_t c_handle, const char* key, int64_t* out_value) { - return nvs_get(handle, key, out_value); + return nvs_get(c_handle, key, out_value); } -extern "C" esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value) +extern "C" esp_err_t nvs_get_u64 (nvs_handle_t c_handle, const char* key, uint64_t* out_value) { - return nvs_get(handle, key, out_value); + return nvs_get(c_handle, key, out_value); } -static esp_err_t nvs_get_str_or_blob(nvs_handle handle, nvs::ItemType type, const char* key, void* out_value, size_t* length) +static esp_err_t nvs_get_str_or_blob(nvs_handle_t c_handle, nvs::ItemType type, const char* key, void* out_value, size_t* length) { Lock lock; ESP_LOGD(TAG, "%s %s", __func__, key); - HandleEntry entry; - auto err = nvs_find_ns_handle(handle, entry); + NVSHandleSimple *handle; + auto err = nvs_find_ns_handle(c_handle, &handle); if (err != ESP_OK) { return err; } size_t dataSize; - err = entry.mStoragePtr->getItemDataSize(entry.mNsIndex, type, key, dataSize); + err = handle->get_item_size(type, key, dataSize); if (err != ESP_OK) { return err; } @@ -445,16 +501,254 @@ static esp_err_t nvs_get_str_or_blob(nvs_handle handle, nvs::ItemType type, cons } *length = dataSize; - return entry.mStoragePtr->readItem(entry.mNsIndex, type, key, out_value, dataSize); + return handle->get_typed_item(type, key, out_value, dataSize); } -extern "C" esp_err_t nvs_get_str(nvs_handle handle, const char* key, char* out_value, size_t* length) +extern "C" esp_err_t nvs_get_str(nvs_handle_t c_handle, const char* key, char* out_value, size_t* length) { - return nvs_get_str_or_blob(handle, nvs::ItemType::SZ, key, out_value, length); + return nvs_get_str_or_blob(c_handle, nvs::ItemType::SZ, key, out_value, length); } -extern "C" esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length) +extern "C" esp_err_t nvs_get_blob(nvs_handle_t c_handle, const char* key, void* out_value, size_t* length) { - return nvs_get_str_or_blob(handle, nvs::ItemType::BLOB, key, out_value, length); + return nvs_get_str_or_blob(c_handle, nvs::ItemType::BLOB, key, out_value, length); } +extern "C" esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats) +{ + Lock lock; + nvs::Storage* pStorage; + + if (nvs_stats == nullptr) { + return ESP_ERR_INVALID_ARG; + } + nvs_stats->used_entries = 0; + nvs_stats->free_entries = 0; + nvs_stats->total_entries = 0; + nvs_stats->namespace_count = 0; + + pStorage = lookup_storage_from_name((part_name == nullptr) ? NVS_DEFAULT_PART_NAME : part_name); + if (pStorage == nullptr) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + if(!pStorage->isValid()){ + return ESP_ERR_NVS_INVALID_STATE; + } + + return pStorage->fillStats(*nvs_stats); +} + +extern "C" esp_err_t nvs_get_used_entry_count(nvs_handle_t c_handle, size_t* used_entries) +{ + Lock lock; + if(used_entries == nullptr){ + return ESP_ERR_INVALID_ARG; + } + *used_entries = 0; + + NVSHandleSimple *handle; + auto err = nvs_find_ns_handle(c_handle, &handle); + if (err != ESP_OK) { + return err; + } + + size_t used_entry_count; + err = handle->get_used_entry_count(used_entry_count); + if(err == ESP_OK){ + *used_entries = used_entry_count; + } + return err; +} + +#if (defined CONFIG_NVS_ENCRYPTION) && (!defined LINUX_TARGET) + +extern "C" esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, nvs_sec_cfg_t* cfg) +{ + auto err = esp_partition_erase_range(partition, 0, partition->size); + if(err != ESP_OK) { + return err; + } + + for(uint8_t cnt = 0; cnt < NVS_KEY_SIZE; cnt++) { + /* Adjacent 16-byte blocks should be different */ + if (((cnt / 16) & 1) == 0) { + cfg->eky[cnt] = 0xff; + cfg->tky[cnt] = 0xee; + } else { + cfg->eky[cnt] = 0x99; + cfg->tky[cnt] = 0x88; + } + } + + /** + * Write key configuration without encryption engine (using raw partition write APIs). + * But the read is decrypted through flash encryption engine. This allows unique NVS encryption configuration, + * as flash encryption key is randomly generated per device. + */ + err = esp_partition_write_raw(partition, 0, cfg->eky, NVS_KEY_SIZE); + if(err != ESP_OK) { + return err; + } + + /* Write without encryption, see note above */ + err = esp_partition_write_raw(partition, NVS_KEY_SIZE, cfg->tky, NVS_KEY_SIZE); + if(err != ESP_OK) { + return err; + } + + err = esp_partition_read(partition, 0, cfg->eky, NVS_KEY_SIZE); + if(err != ESP_OK) { + return err; + } + + err = esp_partition_read(partition, NVS_KEY_SIZE, cfg->tky, NVS_KEY_SIZE); + if(err != ESP_OK) { + return err; + } + + uint32_t crc_calc = crc32_le(0xffffffff, cfg->eky, NVS_KEY_SIZE); + crc_calc = crc32_le(crc_calc, cfg->tky, NVS_KEY_SIZE); + + uint8_t crc_wr[16]; + memset(crc_wr, 0xff, sizeof(crc_wr)); + memcpy(crc_wr, &crc_calc, 4); + + err = esp_partition_write(partition, 2 * NVS_KEY_SIZE, crc_wr, sizeof(crc_wr)); + if(err != ESP_OK) { + return err; + } + + return ESP_OK; + +} + +extern "C" esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partition, nvs_sec_cfg_t* cfg) +{ + uint8_t eky_raw[NVS_KEY_SIZE], tky_raw[NVS_KEY_SIZE]; + uint32_t crc_raw, crc_read, crc_calc; + + auto check_if_initialized = [](uint8_t* eky, uint8_t* tky, uint32_t crc) { + uint8_t cnt = 0; + while(cnt < NVS_KEY_SIZE && eky[cnt] == 0xff && tky[cnt] == 0xff) cnt++; + + if(cnt == NVS_KEY_SIZE && crc == 0xffffffff) { + return false; + } + return true; + }; + + auto err = esp_partition_read_raw(partition, 0, eky_raw, NVS_KEY_SIZE); + if(err != ESP_OK) { + return err; + } + + err = esp_partition_read_raw(partition, NVS_KEY_SIZE, tky_raw, NVS_KEY_SIZE); + if(err != ESP_OK) { + return err; + } + + err = esp_partition_read_raw(partition, 2 * NVS_KEY_SIZE, &crc_raw, 4); + if(err != ESP_OK) { + return err; + } + + if(!check_if_initialized(eky_raw, tky_raw, crc_raw)) { + /* This is an uninitialized key partition*/ + return ESP_ERR_NVS_KEYS_NOT_INITIALIZED; + } + + err = esp_partition_read(partition, 0, cfg->eky, NVS_KEY_SIZE); + + if(err != ESP_OK) { + return err; + } + + err = esp_partition_read(partition, NVS_KEY_SIZE, cfg->tky, NVS_KEY_SIZE); + + if(err != ESP_OK) { + return err; + } + + err = esp_partition_read(partition, 2 * NVS_KEY_SIZE, &crc_read, 4); + + if(err != ESP_OK) { + return err; + } + + crc_calc = crc32_le(0xffffffff, cfg->eky, NVS_KEY_SIZE); + crc_calc = crc32_le(crc_calc, cfg->tky, NVS_KEY_SIZE); + + if(crc_calc != crc_read) { + if(!check_if_initialized(cfg->eky, cfg->tky, crc_read)) { + /* This is an uninitialized key partition*/ + return ESP_ERR_NVS_KEYS_NOT_INITIALIZED; + } + return ESP_ERR_NVS_CORRUPT_KEY_PART; + } + + return ESP_OK; +} + +#endif + +static nvs_iterator_t create_iterator(nvs::Storage *storage, nvs_type_t type) +{ + nvs_iterator_t it = (nvs_iterator_t)calloc(1, sizeof(nvs_opaque_iterator_t)); + if (it == nullptr) { + return nullptr; + } + + it->storage = storage; + it->type = type; + + return it; +} + +extern "C" nvs_iterator_t nvs_entry_find(const char *part_name, const char *namespace_name, nvs_type_t type) +{ + Lock lock; + nvs::Storage *pStorage; + + pStorage = lookup_storage_from_name(part_name); + if (pStorage == nullptr) { + return nullptr; + } + + nvs_iterator_t it = create_iterator(pStorage, type); + if (it == nullptr) { + return nullptr; + } + + bool entryFound = pStorage->findEntry(it, namespace_name); + if (!entryFound) { + free(it); + return nullptr; + } + + return it; +} + +extern "C" nvs_iterator_t nvs_entry_next(nvs_iterator_t it) +{ + Lock lock; + assert(it); + + bool entryFound = it->storage->nextEntry(it); + if (!entryFound) { + free(it); + return nullptr; + } + + return it; +} + +extern "C" void nvs_entry_info(nvs_iterator_t it, nvs_entry_info_t *out_info) +{ + *out_info = it->entry_info; +} + +extern "C" void nvs_release_iterator(nvs_iterator_t it) +{ + free(it); +} diff --git a/components/nvs_flash/src/nvs_cxx_api.cpp b/components/nvs_flash/src/nvs_cxx_api.cpp new file mode 100644 index 000000000..65fb1128b --- /dev/null +++ b/components/nvs_flash/src/nvs_cxx_api.cpp @@ -0,0 +1,68 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "nvs_partition_manager.hpp" +#include "nvs_handle.hpp" +#include "nvs_handle_simple.hpp" +#include "nvs_handle_locked.hpp" +#include "nvs_platform.hpp" + +namespace nvs { + +std::unique_ptr open_nvs_handle_from_partition(const char *partition_name, + const char *ns_name, + nvs_open_mode_t open_mode, + esp_err_t *err) +{ + if (partition_name == nullptr || ns_name == nullptr) { + if (err) { + *err = ESP_ERR_INVALID_ARG; + } + return nullptr; + } + + Lock lock; + + NVSHandleSimple *handle_simple; + esp_err_t result = nvs::NVSPartitionManager::get_instance()-> + open_handle(partition_name, ns_name, open_mode, &handle_simple); + + if (err) { + *err = result; + } + + if (result != ESP_OK) { + return nullptr; + } + + NVSHandleLocked *locked_handle = new (nothrow) NVSHandleLocked(handle_simple); + + if (!locked_handle) { + if (err) { + *err = ESP_ERR_NO_MEM; + } + delete handle_simple; + return nullptr; + } + + return std::unique_ptr(locked_handle); +} + +std::unique_ptr open_nvs_handle(const char *ns_name, + nvs_open_mode_t open_mode, + esp_err_t *err) +{ + return open_nvs_handle_from_partition(NVS_DEFAULT_PART_NAME, ns_name, open_mode, err); +} + +} // namespace nvs diff --git a/components/nvs_flash/src/nvs_encrypted_partition.cpp b/components/nvs_flash/src/nvs_encrypted_partition.cpp new file mode 100644 index 000000000..26e8a3314 --- /dev/null +++ b/components/nvs_flash/src/nvs_encrypted_partition.cpp @@ -0,0 +1,121 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "nvs_encrypted_partition.hpp" +#include "nvs_types.hpp" + +namespace nvs { + +NVSEncryptedPartition::NVSEncryptedPartition(const esp_partition_t *partition) + : NVSPartition(partition) { } + +esp_err_t NVSEncryptedPartition::init(nvs_sec_cfg_t* cfg) +{ + uint8_t* eky = reinterpret_cast(cfg); + + mbedtls_aes_xts_init(&mEctxt); + mbedtls_aes_xts_init(&mDctxt); + + if (mbedtls_aes_xts_setkey_enc(&mEctxt, eky, 2 * NVS_KEY_SIZE * 8) != 0) { + return ESP_ERR_NVS_XTS_CFG_FAILED; + } + + if (mbedtls_aes_xts_setkey_dec(&mDctxt, eky, 2 * NVS_KEY_SIZE * 8) != 0) { + return ESP_ERR_NVS_XTS_CFG_FAILED; + } + + return ESP_OK; +} + +esp_err_t NVSEncryptedPartition::read(size_t src_offset, void* dst, size_t size) +{ + /** Currently upper layer of NVS reads entries one by one even for variable size + * multi-entry data types. So length should always be equal to size of an entry.*/ + if (size != sizeof(Item)) return ESP_ERR_INVALID_SIZE; + + // read data + esp_err_t read_result = esp_partition_read(mESPPartition, src_offset, dst, size); + if (read_result != ESP_OK) { + return read_result; + } + + // decrypt data + //sector num required as an arr by mbedtls. Should have been just uint64/32. + uint8_t data_unit[16]; + + uint32_t relAddr = src_offset; + + memset(data_unit, 0, sizeof(data_unit)); + + memcpy(data_unit, &relAddr, sizeof(relAddr)); + + uint8_t *destination = reinterpret_cast(dst); + + if (mbedtls_aes_crypt_xts(&mDctxt, MBEDTLS_AES_DECRYPT, size, data_unit, destination, destination) != 0) { + return ESP_ERR_NVS_XTS_DECR_FAILED; + } + + return ESP_OK; +} + +esp_err_t NVSEncryptedPartition::write(size_t addr, const void* src, size_t size) +{ + if (size % ESP_ENCRYPT_BLOCK_SIZE != 0) return ESP_ERR_INVALID_SIZE; + + // copy data to buffer for encryption + uint8_t* buf = new (std::nothrow) uint8_t [size]; + + if (!buf) return ESP_ERR_NO_MEM; + + memcpy(buf, src, size); + + // encrypt data + uint8_t entrySize = sizeof(Item); + + //sector num required as an arr by mbedtls. Should have been just uint64/32. + uint8_t data_unit[16]; + + /* Use relative address instead of absolute address (relocatable), so that host-generated + * encrypted nvs images can be used*/ + uint32_t relAddr = addr; + + memset(data_unit, 0, sizeof(data_unit)); + + for(uint8_t entry = 0; entry < (size/entrySize); entry++) + { + uint32_t offset = entry * entrySize; + uint32_t *addr_loc = (uint32_t*) &data_unit[0]; + + *addr_loc = relAddr + offset; + if (mbedtls_aes_crypt_xts(&mEctxt, + MBEDTLS_AES_ENCRYPT, + entrySize, + data_unit, + buf + offset, + buf + offset) != 0) { + delete buf; + return ESP_ERR_NVS_XTS_ENCR_FAILED; + } + } + + // write data + esp_err_t result = esp_partition_write(mESPPartition, addr, buf, size); + + delete buf; + + return result; +} + +} // nvs diff --git a/components/nvs_flash/src/nvs_encrypted_partition.hpp b/components/nvs_flash/src/nvs_encrypted_partition.hpp new file mode 100644 index 000000000..76c0607a0 --- /dev/null +++ b/components/nvs_flash/src/nvs_encrypted_partition.hpp @@ -0,0 +1,43 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef NVS_ENCRYPTED_PARTITION_HPP_ +#define NVS_ENCRYPTED_PARTITION_HPP_ + +#include "mbedtls/aes.h" +#include "nvs_flash.h" +#include "nvs_partition.hpp" + +namespace nvs { + +class NVSEncryptedPartition : public NVSPartition { +public: + NVSEncryptedPartition(const esp_partition_t *partition); + + virtual ~NVSEncryptedPartition() { } + + esp_err_t init(nvs_sec_cfg_t* cfg); + + esp_err_t read(size_t src_offset, void* dst, size_t size) override; + + esp_err_t write(size_t dst_offset, const void* src, size_t size) override; + +protected: + mbedtls_aes_xts_context mEctxt; + mbedtls_aes_xts_context mDctxt; +}; + +} // nvs + +#endif // NVS_ENCRYPTED_PARTITION_HPP_ diff --git a/components/nvs_flash/src/nvs_handle_locked.cpp b/components/nvs_flash/src/nvs_handle_locked.cpp new file mode 100644 index 000000000..89e5cbbca --- /dev/null +++ b/components/nvs_flash/src/nvs_handle_locked.cpp @@ -0,0 +1,82 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "nvs_handle_locked.hpp" + +namespace nvs { + +NVSHandleLocked::NVSHandleLocked(NVSHandleSimple *handle) : handle(handle) { + Lock::init(); +} + +NVSHandleLocked::~NVSHandleLocked() { + Lock lock; + delete handle; +} + +esp_err_t NVSHandleLocked::set_string(const char *key, const char* str) { + Lock lock; + return handle->set_string(key, str); +} + +esp_err_t NVSHandleLocked::set_blob(const char *key, const void* blob, size_t len) { + Lock lock; + return handle->set_blob(key, blob, len); +} + +esp_err_t NVSHandleLocked::get_string(const char *key, char* out_str, size_t len) { + Lock lock; + return handle->get_string(key, out_str, len); +} + +esp_err_t NVSHandleLocked::get_blob(const char *key, void* out_blob, size_t len) { + Lock lock; + return handle->get_blob(key, out_blob, len); +} + +esp_err_t NVSHandleLocked::get_item_size(ItemType datatype, const char *key, size_t &size) { + Lock lock; + return handle->get_item_size(datatype, key, size); +} + +esp_err_t NVSHandleLocked::erase_item(const char* key) { + Lock lock; + return handle->erase_item(key); +} + +esp_err_t NVSHandleLocked::erase_all() { + Lock lock; + return handle->erase_all(); +} + +esp_err_t NVSHandleLocked::commit() { + Lock lock; + return handle->commit(); +} + +esp_err_t NVSHandleLocked::get_used_entry_count(size_t& usedEntries) { + Lock lock; + return handle->get_used_entry_count(usedEntries); +} + +esp_err_t NVSHandleLocked::set_typed_item(ItemType datatype, const char *key, const void* data, size_t dataSize) { + Lock lock; + return handle->set_typed_item(datatype, key, data, dataSize); +} + +esp_err_t NVSHandleLocked::get_typed_item(ItemType datatype, const char *key, void* data, size_t dataSize) { + Lock lock; + return handle->get_typed_item(datatype, key, data, dataSize); +} + +} // namespace nvs diff --git a/components/nvs_flash/src/nvs_handle_locked.hpp b/components/nvs_flash/src/nvs_handle_locked.hpp new file mode 100644 index 000000000..39d514c7a --- /dev/null +++ b/components/nvs_flash/src/nvs_handle_locked.hpp @@ -0,0 +1,66 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef NVS_HANDLE_LOCKED_HPP_ +#define NVS_HANDLE_LOCKED_HPP_ + +#include "nvs_handle_simple.hpp" + +namespace nvs { + +/** + * @brief A class which behaves the same as NVSHandleSimple, except that all public member functions are locked. + * + * This class follows the decorator design pattern. The reason why we don't want locks in NVSHandleSimple is that + * NVSHandleSimple can also be used by the C-API which locks its public functions already. + * Thus, we avoid double-locking. + * + * @note this class becomes responsible for its internal NVSHandleSimple object, i.e. it deletes the handle object on + * destruction + */ +class NVSHandleLocked : public NVSHandle { +public: + NVSHandleLocked(NVSHandleSimple *handle); + + virtual ~NVSHandleLocked(); + + esp_err_t set_string(const char *key, const char* str) override; + + esp_err_t set_blob(const char *key, const void* blob, size_t len) override; + + esp_err_t get_string(const char *key, char* out_str, size_t len) override; + + esp_err_t get_blob(const char *key, void* out_blob, size_t len) override; + + esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) override; + + esp_err_t erase_item(const char* key) override; + + esp_err_t erase_all() override; + + esp_err_t commit() override; + + esp_err_t get_used_entry_count(size_t& usedEntries) override; + +protected: + esp_err_t set_typed_item(ItemType datatype, const char *key, const void* data, size_t dataSize) override; + + esp_err_t get_typed_item(ItemType datatype, const char *key, void* data, size_t dataSize) override; + +private: + NVSHandleSimple *handle; +}; + +} // namespace nvs + +#endif // NVS_HANDLE_LOCKED_HPP_ diff --git a/components/nvs_flash/src/nvs_handle_simple.cpp b/components/nvs_flash/src/nvs_handle_simple.cpp new file mode 100644 index 000000000..348e197b7 --- /dev/null +++ b/components/nvs_flash/src/nvs_handle_simple.cpp @@ -0,0 +1,137 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include "nvs_handle.hpp" +#include "nvs_partition_manager.hpp" + +namespace nvs { + +NVSHandleSimple::~NVSHandleSimple() { + NVSPartitionManager::get_instance()->close_handle(this); +} + +esp_err_t NVSHandleSimple::set_typed_item(ItemType datatype, const char *key, const void* data, size_t dataSize) +{ + if (!valid) return ESP_ERR_NVS_INVALID_HANDLE; + if (mReadOnly) return ESP_ERR_NVS_READ_ONLY; + + return mStoragePtr->writeItem(mNsIndex, datatype, key, data, dataSize); +} + +esp_err_t NVSHandleSimple::get_typed_item(ItemType datatype, const char *key, void* data, size_t dataSize) +{ + if (!valid) return ESP_ERR_NVS_INVALID_HANDLE; + + return mStoragePtr->readItem(mNsIndex, datatype, key, data, dataSize); +} + +esp_err_t NVSHandleSimple::set_string(const char *key, const char* str) +{ + if (!valid) return ESP_ERR_NVS_INVALID_HANDLE; + if (mReadOnly) return ESP_ERR_NVS_READ_ONLY; + + return mStoragePtr->writeItem(mNsIndex, nvs::ItemType::SZ, key, str, strlen(str) + 1); +} + +esp_err_t NVSHandleSimple::set_blob(const char *key, const void* blob, size_t len) +{ + if (!valid) return ESP_ERR_NVS_INVALID_HANDLE; + if (mReadOnly) return ESP_ERR_NVS_READ_ONLY; + + return mStoragePtr->writeItem(mNsIndex, nvs::ItemType::BLOB, key, blob, len); +} + +esp_err_t NVSHandleSimple::get_string(const char *key, char* out_str, size_t len) +{ + if (!valid) return ESP_ERR_NVS_INVALID_HANDLE; + + return mStoragePtr->readItem(mNsIndex, nvs::ItemType::SZ, key, out_str, len); +} + +esp_err_t NVSHandleSimple::get_blob(const char *key, void* out_blob, size_t len) +{ + if (!valid) return ESP_ERR_NVS_INVALID_HANDLE; + + return mStoragePtr->readItem(mNsIndex, nvs::ItemType::BLOB, key, out_blob, len); +} + +esp_err_t NVSHandleSimple::get_item_size(ItemType datatype, const char *key, size_t &size) +{ + if (!valid) return ESP_ERR_NVS_INVALID_HANDLE; + + return mStoragePtr->getItemDataSize(mNsIndex, datatype, key, size); +} + +esp_err_t NVSHandleSimple::erase_item(const char* key) +{ + if (!valid) return ESP_ERR_NVS_INVALID_HANDLE; + if (mReadOnly) return ESP_ERR_NVS_READ_ONLY; + + return mStoragePtr->eraseItem(mNsIndex, key); +} + +esp_err_t NVSHandleSimple::erase_all() +{ + if (!valid) return ESP_ERR_NVS_INVALID_HANDLE; + if (mReadOnly) return ESP_ERR_NVS_READ_ONLY; + + return mStoragePtr->eraseNamespace(mNsIndex); +} + +esp_err_t NVSHandleSimple::commit() +{ + if (!valid) return ESP_ERR_NVS_INVALID_HANDLE; + + return ESP_OK; +} + +esp_err_t NVSHandleSimple::get_used_entry_count(size_t& used_entries) +{ + used_entries = 0; + + if (!valid) return ESP_ERR_NVS_INVALID_HANDLE; + + size_t used_entry_count; + esp_err_t err = mStoragePtr->calcEntriesInNamespace(mNsIndex, used_entry_count); + if(err == ESP_OK){ + used_entries = used_entry_count; + } + return err; +} + +void NVSHandleSimple::debugDump() { + return mStoragePtr->debugDump(); +} + +esp_err_t NVSHandleSimple::fillStats(nvs_stats_t& nvsStats) { + return mStoragePtr->fillStats(nvsStats); +} + +esp_err_t NVSHandleSimple::calcEntriesInNamespace(size_t& usedEntries) { + return mStoragePtr->calcEntriesInNamespace(mNsIndex, usedEntries); +} + +bool NVSHandleSimple::findEntry(nvs_opaque_iterator_t* it, const char* name) { + return mStoragePtr->findEntry(it, name); +} + +bool NVSHandleSimple::nextEntry(nvs_opaque_iterator_t* it) { + return mStoragePtr->nextEntry(it); +} + +const char *NVSHandleSimple::get_partition_name() const { + return mStoragePtr->getPartName(); +} + +} diff --git a/components/nvs_flash/src/nvs_handle_simple.hpp b/components/nvs_flash/src/nvs_handle_simple.hpp new file mode 100644 index 000000000..0a20aa4e8 --- /dev/null +++ b/components/nvs_flash/src/nvs_handle_simple.hpp @@ -0,0 +1,107 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef NVS_HANDLE_SIMPLE_HPP_ +#define NVS_HANDLE_SIMPLE_HPP_ + +#include "intrusive_list.h" +#include "nvs_storage.hpp" +#include "nvs_platform.hpp" + +#include "nvs_handle.hpp" + +namespace nvs { + +/** + * @brief This class implements NVSHandle according to the ESP32's flash and partitioning scheme. + * + * It is used by both the C API and the C++ API. The main responsibility is to check whether the handle is valid + * and in the right read/write mode and then forward the calls to the storage object. + * + * For more details about the general member functions, see nvs_handle.hpp. + */ +class NVSHandleSimple : public intrusive_list_node, public NVSHandle { + friend class NVSPartitionManager; +public: + NVSHandleSimple(bool readOnly, uint8_t nsIndex, Storage *StoragePtr) : + mStoragePtr(StoragePtr), + mNsIndex(nsIndex), + mReadOnly(readOnly), + valid(1) + { } + + ~NVSHandleSimple(); + + esp_err_t set_typed_item(ItemType datatype, const char *key, const void *data, size_t dataSize) override; + + esp_err_t get_typed_item(ItemType datatype, const char *key, void *data, size_t dataSize) override; + + esp_err_t set_string(const char *key, const char *str) override; + + esp_err_t set_blob(const char *key, const void *blob, size_t len) override; + + esp_err_t get_string(const char *key, char *out_str, size_t len) override; + + esp_err_t get_blob(const char *key, void *out_blob, size_t len) override; + + esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) override; + + esp_err_t erase_item(const char *key) override; + + esp_err_t erase_all() override; + + esp_err_t commit() override; + + esp_err_t get_used_entry_count(size_t &usedEntries) override; + + esp_err_t getItemDataSize(ItemType datatype, const char *key, size_t &dataSize); + + void debugDump(); + + esp_err_t fillStats(nvs_stats_t &nvsStats); + + esp_err_t calcEntriesInNamespace(size_t &usedEntries); + + bool findEntry(nvs_opaque_iterator_t *it, const char *name); + + bool nextEntry(nvs_opaque_iterator_t *it); + + const char *get_partition_name() const; + +private: + /** + * The underlying storage's object. + */ + Storage *mStoragePtr; + + /** + * Numeric representation of the namespace as it is saved in flash (see README.rst for further details). + */ + uint8_t mNsIndex; + + /** + * Whether this handle is marked as read-only or read-write. + * 0 indicates read-only, any other value read-write. + */ + uint8_t mReadOnly; + + /** + * Indicates the validity of this handle. + * Upon opening, a handle is valid. It becomes invalid if the underlying storage is de-initialized. + */ + uint8_t valid; +}; + +} // nvs + +#endif // NVS_HANDLE_SIMPLE_HPP_ diff --git a/components/nvs_flash/src/nvs_item_hash_list.cpp b/components/nvs_flash/src/nvs_item_hash_list.cpp index 845dd0910..7e1c1241a 100644 --- a/components/nvs_flash/src/nvs_item_hash_list.cpp +++ b/components/nvs_flash/src/nvs_item_hash_list.cpp @@ -20,7 +20,7 @@ namespace nvs HashList::HashList() { } - + void HashList::clear() { for (auto it = mBlockList.begin(); it != mBlockList.end();) { @@ -30,7 +30,7 @@ void HashList::clear() delete static_cast(tmp); } } - + HashList::~HashList() { clear(); @@ -42,7 +42,7 @@ HashList::HashListBlock::HashListBlock() "cache block size calculation incorrect"); } -void HashList::insert(const Item& item, size_t index) +esp_err_t HashList::insert(const Item& item, size_t index) { const uint32_t hash_24 = item.calculateCrc32WithoutValue() & 0xffffff; // add entry to the end of last block if possible @@ -50,29 +50,41 @@ void HashList::insert(const Item& item, size_t index) auto& block = mBlockList.back(); if (block.mCount < HashListBlock::ENTRY_COUNT) { block.mNodes[block.mCount++] = HashListNode(hash_24, index); - return; + return ESP_OK; } } // if the above failed, create a new block and add entry to it - HashListBlock* newBlock = new HashListBlock; + HashListBlock* newBlock = new (std::nothrow) HashListBlock; + + if (!newBlock) return ESP_ERR_NO_MEM; + mBlockList.push_back(newBlock); newBlock->mNodes[0] = HashListNode(hash_24, index); newBlock->mCount++; + + return ESP_OK; } void HashList::erase(size_t index, bool itemShouldExist) { for (auto it = mBlockList.begin(); it != mBlockList.end();) { bool haveEntries = false; + bool foundIndex = false; for (size_t i = 0; i < it->mCount; ++i) { if (it->mNodes[i].mIndex == index) { it->mNodes[i].mIndex = 0xff; - return; + foundIndex = true; + /* found the item and removed it */ } if (it->mNodes[i].mIndex != 0xff) { haveEntries = true; } + if (haveEntries && foundIndex) { + /* item was found, and HashListBlock still has some items */ + return; + } } + /* no items left in HashListBlock, can remove */ if (!haveEntries) { auto tmp = it; ++it; @@ -81,6 +93,10 @@ void HashList::erase(size_t index, bool itemShouldExist) } else { ++it; } + if (foundIndex) { + /* item was found and empty HashListBlock was removed */ + return; + } } if (itemShouldExist) { assert(false && "item should have been present in cache"); diff --git a/components/nvs_flash/src/nvs_item_hash_list.hpp b/components/nvs_flash/src/nvs_item_hash_list.hpp index e759cd818..ca21c92c1 100644 --- a/components/nvs_flash/src/nvs_item_hash_list.hpp +++ b/components/nvs_flash/src/nvs_item_hash_list.hpp @@ -27,16 +27,16 @@ class HashList public: HashList(); ~HashList(); - - void insert(const Item& item, size_t index); + + esp_err_t insert(const Item& item, size_t index); void erase(const size_t index, bool itemShouldExist=true); size_t find(size_t start, const Item& item); void clear(); - + private: HashList(const HashList& other); const HashList& operator= (const HashList& rhs); - + protected: struct HashListNode { diff --git a/components/nvs_flash/src/nvs_page.cpp b/components/nvs_flash/src/nvs_page.cpp index acbae5358..2f72a2090 100644 --- a/components/nvs_flash/src/nvs_page.cpp +++ b/components/nvs_flash/src/nvs_page.cpp @@ -12,28 +12,39 @@ // See the License for the specific language governing permissions and // limitations under the License. #include "nvs_page.hpp" -#include +#if defined(LINUX_TARGET) +#include "crc.h" +#else +#include +#endif #include #include namespace nvs { +Page::Page() : mPartition(nullptr) { } + uint32_t Page::Header::calculateCrc32() { - return crc32_le(0xffffffff, + return esp_rom_crc32_le(0xffffffff, reinterpret_cast(this) + offsetof(Header, mSeqNumber), offsetof(Header, mCrc32) - offsetof(Header, mSeqNumber)); } -esp_err_t Page::load(uint32_t sectorNumber) +esp_err_t Page::load(Partition *partition, uint32_t sectorNumber) { + if (partition == nullptr) { + return ESP_ERR_INVALID_ARG; + } + + mPartition = partition; mBaseAddress = sectorNumber * SEC_SIZE; mUsedEntryCount = 0; mErasedEntryCount = 0; Header header; - auto rc = spi_flash_read(mBaseAddress, &header, sizeof(header)); + auto rc = mPartition->read_raw(mBaseAddress, &header, sizeof(header)); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -42,24 +53,35 @@ esp_err_t Page::load(uint32_t sectorNumber) mState = header.mState; // check if the whole page is really empty // reading the whole page takes ~40 times less than erasing it - uint32_t line[8]; - for (uint32_t i = 0; i < SPI_FLASH_SEC_SIZE; i += sizeof(line)) { - rc = spi_flash_read(mBaseAddress + i, line, sizeof(line)); + const int BLOCK_SIZE = 128; + uint32_t* block = new (std::nothrow) uint32_t[BLOCK_SIZE]; + + if (!block) return ESP_ERR_NO_MEM; + + for (uint32_t i = 0; i < SPI_FLASH_SEC_SIZE; i += 4 * BLOCK_SIZE) { + rc = mPartition->read_raw(mBaseAddress + i, block, 4 * BLOCK_SIZE); if (rc != ESP_OK) { mState = PageState::INVALID; + delete[] block; return rc; } - if (std::any_of(line, line + 4, [](uint32_t val) -> bool { return val != 0xffffffff; })) { + if (std::any_of(block, block + BLOCK_SIZE, [](uint32_t val) -> bool { return val != 0xffffffff; })) { // page isn't as empty after all, mark it as corrupted mState = PageState::CORRUPT; break; } } + delete[] block; } else if (header.mCrc32 != header.calculateCrc32()) { header.mState = PageState::CORRUPT; } else { mState = header.mState; mSeqNumber = header.mSeqNumber; + if(header.mVersion < NVS_VERSION) { + return ESP_ERR_NVS_NEW_VERSION_FOUND; + } else { + mVersion = header.mVersion; + } } switch (mState) { @@ -82,13 +104,16 @@ esp_err_t Page::load(uint32_t sectorNumber) esp_err_t Page::writeEntry(const Item& item) { - auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), &item, sizeof(item)); - if (rc != ESP_OK) { + esp_err_t err; + + err = mPartition->write(getEntryAddress(mNextFreeEntry), &item, sizeof(item)); + + if (err != ESP_OK) { mState = PageState::INVALID; - return rc; + return err; } - auto err = alterEntryState(mNextFreeEntry, EntryState::WRITTEN); + err = alterEntryState(mNextFreeEntry, EntryState::WRITTEN); if (err != ESP_OK) { return err; } @@ -102,17 +127,18 @@ esp_err_t Page::writeEntry(const Item& item) return ESP_OK; } - + esp_err_t Page::writeEntryData(const uint8_t* data, size_t size) { assert(size % ENTRY_SIZE == 0); assert(mNextFreeEntry != INVALID_ENTRY); assert(mFirstUsedEntry != INVALID_ENTRY); const uint16_t count = size / ENTRY_SIZE; - + const uint8_t* buf = data; - -#ifdef ESP_PLATFORM + +#if !defined LINUX_TARGET + // TODO: check whether still necessary with esp_partition* API /* On the ESP32, data can come from DROM, which is not accessible by spi_flash_write * function. To work around this, we copy the data to heap if it came from DROM. * Hopefully this won't happen very often in practice. For data from DRAM, we should @@ -127,13 +153,15 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size) } memcpy((void*)buf, data, size); } -#endif //ESP_PLATFORM - auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), buf, size); -#ifdef ESP_PLATFORM +#endif // ! LINUX_TARGET + + auto rc = mPartition->write(getEntryAddress(mNextFreeEntry), buf, size); + +#if !defined LINUX_TARGET if (buf != data) { free((void*)buf); } -#endif //ESP_PLATFORM +#endif // ! LINUX_TARGET if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -147,15 +175,15 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size) return ESP_OK; } -esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize) +esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize, uint8_t chunkIdx) { Item item; esp_err_t err; - + if (mState == PageState::INVALID) { return ESP_ERR_NVS_INVALID_STATE; } - + if (mState == PageState::UNINITIALIZED) { err = initialize(); if (err != ESP_OK) { @@ -171,21 +199,22 @@ esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, c if (keySize > Item::MAX_KEY_LENGTH) { return ESP_ERR_NVS_KEY_TOO_LONG; } - - if (dataSize > Page::BLOB_MAX_SIZE) { + + if (dataSize > Page::CHUNK_MAX_SIZE) { return ESP_ERR_NVS_VALUE_TOO_LONG; } size_t totalSize = ENTRY_SIZE; size_t entriesCount = 1; - if (datatype == ItemType::SZ || datatype == ItemType::BLOB) { + if (isVariableLengthType(datatype)) { size_t roundedSize = (dataSize + ENTRY_SIZE - 1) & ~(ENTRY_SIZE - 1); totalSize += roundedSize; entriesCount += roundedSize / ENTRY_SIZE; } // primitive types should fit into one entry - assert(totalSize == ENTRY_SIZE || datatype == ItemType::BLOB || datatype == ItemType::SZ); + assert(totalSize == ENTRY_SIZE || + isVariableLengthType(datatype)); if (mNextFreeEntry == INVALID_ENTRY || mNextFreeEntry + entriesCount > ENTRY_COUNT) { // page will not fit this amount of data @@ -194,10 +223,14 @@ esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, c // write first item size_t span = (totalSize + ENTRY_SIZE - 1) / ENTRY_SIZE; - item = Item(nsIndex, datatype, span, key); - mHashList.insert(item, mNextFreeEntry); + item = Item(nsIndex, datatype, span, key, chunkIdx); + err = mHashList.insert(item, mNextFreeEntry); - if (datatype != ItemType::SZ && datatype != ItemType::BLOB) { + if (err != ESP_OK) { + return err; + } + + if (!isVariableLengthType(datatype)) { memcpy(item.data, data, dataSize); item.crc32 = item.calculateCrc32(); err = writeEntry(item); @@ -208,7 +241,7 @@ esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, c const uint8_t* src = reinterpret_cast(data); item.varLength.dataCrc32 = Item::calculateCrc32(src, dataSize); item.varLength.dataSize = dataSize; - item.varLength.reserved2 = 0xffff; + item.varLength.reserved = 0xffff; item.crc32 = item.calculateCrc32(); err = writeEntry(item); if (err != ESP_OK) { @@ -222,36 +255,36 @@ esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, c return err; } } - + size_t tail = dataSize - left; if (tail > 0) { - std::fill_n(item.rawData, ENTRY_SIZE / 4, 0xffffffff); + std::fill_n(item.rawData, ENTRY_SIZE, 0xff); memcpy(item.rawData, static_cast(data) + left, tail); err = writeEntry(item); if (err != ESP_OK) { return err; } } - + } return ESP_OK; } -esp_err_t Page::readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize) +esp_err_t Page::readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize, uint8_t chunkIdx, VerOffset chunkStart) { size_t index = 0; Item item; - + if (mState == PageState::INVALID) { return ESP_ERR_NVS_INVALID_STATE; } - - esp_err_t rc = findItem(nsIndex, datatype, key, index, item); + + esp_err_t rc = findItem(nsIndex, datatype, key, index, item, chunkIdx, chunkStart); if (rc != ESP_OK) { return rc; } - if (datatype != ItemType::SZ && datatype != ItemType::BLOB) { + if (!isVariableLengthType(datatype)) { if (dataSize != getAlignmentForType(datatype)) { return ESP_ERR_NVS_TYPE_MISMATCH; } @@ -288,22 +321,74 @@ esp_err_t Page::readItem(uint8_t nsIndex, ItemType datatype, const char* key, vo return ESP_OK; } -esp_err_t Page::eraseItem(uint8_t nsIndex, ItemType datatype, const char* key) +esp_err_t Page::cmpItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize, uint8_t chunkIdx, VerOffset chunkStart) { size_t index = 0; Item item; - esp_err_t rc = findItem(nsIndex, datatype, key, index, item); + + if (mState == PageState::INVALID) { + return ESP_ERR_NVS_INVALID_STATE; + } + + esp_err_t rc = findItem(nsIndex, datatype, key, index, item, chunkIdx, chunkStart); + if (rc != ESP_OK) { + return rc; + } + + if (!isVariableLengthType(datatype)) { + if (dataSize != getAlignmentForType(datatype)) { + return ESP_ERR_NVS_TYPE_MISMATCH; + } + + if (memcmp(data, item.data, dataSize)) { + return ESP_ERR_NVS_CONTENT_DIFFERS; + } + return ESP_OK; + } + + if (dataSize < static_cast(item.varLength.dataSize)) { + return ESP_ERR_NVS_INVALID_LENGTH; + } + + const uint8_t* dst = reinterpret_cast(data); + size_t left = item.varLength.dataSize; + for (size_t i = index + 1; i < index + item.span; ++i) { + Item ditem; + rc = readEntry(i, ditem); + if (rc != ESP_OK) { + return rc; + } + size_t willCopy = ENTRY_SIZE; + willCopy = (left < willCopy)?left:willCopy; + if (memcmp(dst, ditem.rawData, willCopy)) { + return ESP_ERR_NVS_CONTENT_DIFFERS; + } + left -= willCopy; + dst += willCopy; + } + if (Item::calculateCrc32(reinterpret_cast(data), item.varLength.dataSize) != item.varLength.dataCrc32) { + return ESP_ERR_NVS_NOT_FOUND; + } + + return ESP_OK; +} + +esp_err_t Page::eraseItem(uint8_t nsIndex, ItemType datatype, const char* key, uint8_t chunkIdx, VerOffset chunkStart) +{ + size_t index = 0; + Item item; + esp_err_t rc = findItem(nsIndex, datatype, key, index, item, chunkIdx, chunkStart); if (rc != ESP_OK) { return rc; } return eraseEntryAndSpan(index); } -esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key) +esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, uint8_t chunkIdx, VerOffset chunkStart) { size_t index = 0; Item item; - return findItem(nsIndex, datatype, key, index, item); + return findItem(nsIndex, datatype, key, index, item, chunkIdx, chunkStart); } esp_err_t Page::eraseEntryAndSpan(size_t index) @@ -406,7 +491,11 @@ esp_err_t Page::copyItems(Page& other) return err; } - other.mHashList.insert(entry, other.mNextFreeEntry); + err = other.mHashList.insert(entry, other.mNextFreeEntry); + if (err != ESP_OK) { + return err; + } + err = other.writeEntry(entry); if (err != ESP_OK) { return err; @@ -435,7 +524,7 @@ esp_err_t Page::mLoadEntryTable() if (mState == PageState::ACTIVE || mState == PageState::FULL || mState == PageState::FREEING) { - auto rc = spi_flash_read(mBaseAddress + ENTRY_TABLE_OFFSET, mEntryTable.data(), + auto rc = mPartition->read_raw(mBaseAddress + ENTRY_TABLE_OFFSET, mEntryTable.data(), mEntryTable.byteSize()); if (rc != ESP_OK) { mState = PageState::INVALID; @@ -474,7 +563,7 @@ esp_err_t Page::mLoadEntryTable() while (mNextFreeEntry < ENTRY_COUNT) { uint32_t entryAddress = getEntryAddress(mNextFreeEntry); uint32_t header; - auto rc = spi_flash_read(entryAddress, &header, sizeof(header)); + auto rc = mPartition->read_raw(entryAddress, &header, sizeof(header)); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -519,7 +608,7 @@ esp_err_t Page::mLoadEntryTable() mState = PageState::INVALID; return err; } - + if (item.crc32 != item.calculateCrc32()) { err = eraseEntryAndSpan(i); if (err != ESP_OK) { @@ -529,12 +618,16 @@ esp_err_t Page::mLoadEntryTable() continue; } - mHashList.insert(item, i); + err = mHashList.insert(item, i); + if (err != ESP_OK) { + mState = PageState::INVALID; + return err; + } // search for potential duplicate item size_t duplicateIndex = mHashList.find(0, item); - - if (item.datatype == ItemType::BLOB || item.datatype == ItemType::SZ) { + + if (isVariableLengthType(item.datatype)) { span = item.span; bool needErase = false; for (size_t j = i; j < i + span; ++j) { @@ -549,7 +642,11 @@ esp_err_t Page::mLoadEntryTable() continue; } } - + + /* Note that logic for duplicate detections works fine even + * when old-format blob is present along with new-format blob-index + * for same key on active page. Since datatype is not used in hash calculation, + * old-format blob will be removed.*/ if (duplicateIndex < i) { eraseEntryAndSpan(duplicateIndex); } @@ -592,12 +689,18 @@ esp_err_t Page::mLoadEntryTable() } continue; } + assert(item.span > 0); - mHashList.insert(item, i); + err = mHashList.insert(item, i); + if (err != ESP_OK) { + mState = PageState::INVALID; + return err; + } + size_t span = item.span; - if (item.datatype == ItemType::BLOB || item.datatype == ItemType::SZ) { + if (isVariableLengthType(item.datatype)) { for (size_t j = i + 1; j < i + span; ++j) { if (mEntryTable.get(j) != EntryState::WRITTEN) { eraseEntryAndSpan(i); @@ -622,9 +725,10 @@ esp_err_t Page::initialize() Header header; header.mState = mState; header.mSeqNumber = mSeqNumber; + header.mVersion = mVersion; header.mCrc32 = header.calculateCrc32(); - auto rc = spi_flash_write(mBaseAddress, &header, sizeof(header)); + auto rc = mPartition->write_raw(mBaseAddress, &header, sizeof(header)); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -641,7 +745,7 @@ esp_err_t Page::alterEntryState(size_t index, EntryState state) mEntryTable.set(index, state); size_t wordToWrite = mEntryTable.getWordIndex(index); uint32_t word = mEntryTable.data()[wordToWrite]; - auto rc = spi_flash_write(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast(wordToWrite) * 4, + auto rc = mPartition->write_raw(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast(wordToWrite) * 4, &word, sizeof(word)); if (rc != ESP_OK) { mState = PageState::INVALID; @@ -665,7 +769,7 @@ esp_err_t Page::alterEntryRangeState(size_t begin, size_t end, EntryState state) } if (nextWordIndex != wordIndex) { uint32_t word = mEntryTable.data()[wordIndex]; - auto rc = spi_flash_write(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast(wordIndex) * 4, + auto rc = mPartition->write_raw(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast(wordIndex) * 4, &word, 4); if (rc != ESP_OK) { return rc; @@ -679,7 +783,7 @@ esp_err_t Page::alterEntryRangeState(size_t begin, size_t end, EntryState state) esp_err_t Page::alterPageState(PageState state) { uint32_t state_val = static_cast(state); - auto rc = spi_flash_write(mBaseAddress, &state_val, sizeof(state)); + auto rc = mPartition->write_raw(mBaseAddress, &state_val, sizeof(state)); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -690,19 +794,19 @@ esp_err_t Page::alterPageState(PageState state) esp_err_t Page::readEntry(size_t index, Item& dst) const { - auto rc = spi_flash_read(getEntryAddress(index), &dst, sizeof(dst)); + auto rc = mPartition->read(getEntryAddress(index), &dst, sizeof(dst)); if (rc != ESP_OK) { return rc; } return ESP_OK; } -esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, size_t &itemIndex, Item& item) +esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, size_t &itemIndex, Item& item, uint8_t chunkIdx, VerOffset chunkStart) { if (mState == PageState::CORRUPT || mState == PageState::INVALID || mState == PageState::UNINITIALIZED) { return ESP_ERR_NVS_NOT_FOUND; } - + size_t findBeginIndex = itemIndex; if (findBeginIndex >= ENTRY_COUNT) { return ESP_ERR_NVS_NOT_FOUND; @@ -719,7 +823,7 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, si } if (nsIndex != NS_ANY && datatype != ItemType::ANY && key != NULL) { - size_t cachedIndex = mHashList.find(start, Item(nsIndex, datatype, 0, key)); + size_t cachedIndex = mHashList.find(start, Item(nsIndex, datatype, 0, key, chunkIdx)); if (cachedIndex < ENTRY_COUNT) { start = cachedIndex; } else { @@ -750,7 +854,7 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, si continue; } - if (item.datatype == ItemType::BLOB || item.datatype == ItemType::SZ) { + if (isVariableLengthType(item.datatype)) { next = i + item.span; } @@ -761,8 +865,31 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, si if (key != nullptr && strncmp(key, item.key, Item::MAX_KEY_LENGTH) != 0) { continue; } + /* For blob data, chunkIndex should match*/ + if (chunkIdx != CHUNK_ANY + && datatype == ItemType::BLOB_DATA + && item.chunkIndex != chunkIdx) { + continue; + } + /* Blob-index will match the with blob data. + * Skip data chunks when searching for blob index*/ + if (datatype == ItemType::BLOB_IDX + && item.chunkIndex != CHUNK_ANY) { + continue; + } + /* Match the version for blob-index*/ + if (datatype == ItemType::BLOB_IDX + && chunkStart != VerOffset::VER_ANY + && item.blobIndex.chunkStart != chunkStart) { + continue; + } + if (datatype != ItemType::ANY && item.datatype != datatype) { + if (key == nullptr && nsIndex == NS_ANY && chunkIdx == CHUNK_ANY) { + continue; // continue for bruteforce search on blob indices. + } + itemIndex = i; return ESP_ERR_NVS_TYPE_MISMATCH; } @@ -793,10 +920,18 @@ esp_err_t Page::setSeqNumber(uint32_t seqNumber) return ESP_OK; } +esp_err_t Page::setVersion(uint8_t ver) +{ + if (mState != PageState::UNINITIALIZED) { + return ESP_ERR_NVS_INVALID_STATE; + } + mVersion = ver; + return ESP_OK; +} + esp_err_t Page::erase() { - auto sector = mBaseAddress / SPI_FLASH_SEC_SIZE; - auto rc = spi_flash_erase_sector(sector); + auto rc = mPartition->erase_range(mBaseAddress, SPI_FLASH_SEC_SIZE); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -825,28 +960,39 @@ esp_err_t Page::markFull() } return alterPageState(PageState::FULL); } - + +size_t Page::getVarDataTailroom() const +{ + if (mState == PageState::UNINITIALIZED) { + return CHUNK_MAX_SIZE; + } else if (mState == PageState::FULL) { + return 0; + } + /* Skip one entry for blob data item precessing the data */ + return ((mNextFreeEntry < (ENTRY_COUNT-1)) ? ((ENTRY_COUNT - mNextFreeEntry - 1) * ENTRY_SIZE): 0); +} + const char* Page::pageStateToName(PageState ps) { switch (ps) { case PageState::CORRUPT: return "CORRUPT"; - + case PageState::ACTIVE: return "ACTIVE"; - + case PageState::FREEING: return "FREEING"; - + case PageState::FULL: return "FULL"; - + case PageState::INVALID: return "INVALID"; - + case PageState::UNINITIALIZED: return "UNINITIALIZED"; - + default: assert(0 && "invalid state value"); return ""; @@ -868,7 +1014,7 @@ void Page::debugDump() const Item item; readEntry(i, item); if (skip == 0) { - printf("W ns=%2u type=%2u span=%3u key=\"%s\" len=%d\n", item.nsIndex, static_cast(item.datatype), item.span, item.key, (item.span != 1)?((int)item.varLength.dataSize):-1); + printf("W ns=%2u type=%2u span=%3u key=\"%s\" chunkIdx=%d len=%d\n", item.nsIndex, static_cast(item.datatype), item.span, item.key, item.chunkIndex, (item.span != 1)?((int)item.varLength.dataSize):-1); if (item.span > 0 && item.span <= ENTRY_COUNT - i) { skip = item.span - 1; } else { @@ -882,4 +1028,33 @@ void Page::debugDump() const } } +esp_err_t Page::calcEntries(nvs_stats_t &nvsStats) +{ + assert(mState != PageState::FREEING); + + nvsStats.total_entries += ENTRY_COUNT; + + switch (mState) { + case PageState::UNINITIALIZED: + case PageState::CORRUPT: + nvsStats.free_entries += ENTRY_COUNT; + break; + + case PageState::FULL: + case PageState::ACTIVE: + nvsStats.used_entries += mUsedEntryCount; + nvsStats.free_entries += ENTRY_COUNT - mUsedEntryCount; // it's equivalent free + erase entries. + break; + + case PageState::INVALID: + return ESP_ERR_INVALID_STATE; + break; + + default: + assert(false && "Unhandled state"); + break; + } + return ESP_OK; +} + } // namespace nvs diff --git a/components/nvs_flash/src/nvs_page.hpp b/components/nvs_flash/src/nvs_page.hpp index 413da4589..5857f1ffe 100644 --- a/components/nvs_flash/src/nvs_page.hpp +++ b/components/nvs_flash/src/nvs_page.hpp @@ -24,6 +24,7 @@ #include "compressed_enum_table.hpp" #include "intrusive_list.h" #include "nvs_item_hash_list.hpp" +#include "partition.hpp" namespace nvs { @@ -45,12 +46,16 @@ class Page : public intrusive_list_node static const size_t ENTRY_SIZE = 32; static const size_t ENTRY_COUNT = 126; static const uint32_t INVALID_ENTRY = 0xffffffff; - - static const size_t BLOB_MAX_SIZE = ENTRY_SIZE * (ENTRY_COUNT / 2 - 1); + + static const size_t CHUNK_MAX_SIZE = ENTRY_SIZE * (ENTRY_COUNT - 1); static const uint8_t NS_INDEX = 0; static const uint8_t NS_ANY = 255; + static const uint8_t CHUNK_ANY = Item::CHUNK_ANY; + + static const uint8_t NVS_VERSION = 0xfe; // Decrement to upgrade + enum class PageState : uint32_t { // All bits set, default state after flash erase. Page has not been initialized yet. UNINITIALIZED = 0xffffffff, @@ -73,26 +78,32 @@ class Page : public intrusive_list_node INVALID = 0 }; + Page(); + PageState state() const { return mState; } - esp_err_t load(uint32_t sectorNumber); + esp_err_t load(Partition *partition, uint32_t sectorNumber); esp_err_t getSeqNumber(uint32_t& seqNumber) const; esp_err_t setSeqNumber(uint32_t seqNumber); - esp_err_t writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize); + esp_err_t setVersion(uint8_t version); - esp_err_t readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize); + esp_err_t writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize, uint8_t chunkIdx = CHUNK_ANY); - esp_err_t eraseItem(uint8_t nsIndex, ItemType datatype, const char* key); + esp_err_t readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize, uint8_t chunkIdx = CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY); - esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key); + esp_err_t cmpItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize, uint8_t chunkIdx = CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY); - esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, size_t &itemIndex, Item& item); + esp_err_t eraseItem(uint8_t nsIndex, ItemType datatype, const char* key, uint8_t chunkIdx = CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY); + + esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, uint8_t chunkIdx = CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY); + + esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, size_t &itemIndex, Item& item, uint8_t chunkIdx = CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY); template esp_err_t writeItem(uint8_t nsIndex, const char* key, const T& value) @@ -106,6 +117,12 @@ class Page : public intrusive_list_node return readItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value)); } + template + esp_err_t cmpItem(uint8_t nsIndex, const char* key, const T& value) + { + return cmpItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value)); + } + template esp_err_t eraseItem(uint8_t nsIndex, const char* key) { @@ -121,7 +138,7 @@ class Page : public intrusive_list_node { return mErasedEntryCount; } - + size_t getVarDataTailroom() const ; esp_err_t markFull(); @@ -133,6 +150,8 @@ class Page : public intrusive_list_node void debugDump() const; + esp_err_t calcEntries(nvs_stats_t &nvsStats); + protected: class Header @@ -140,12 +159,13 @@ class Page : public intrusive_list_node public: Header() { - std::fill_n(mReserved, sizeof(mReserved)/sizeof(mReserved[0]), UINT32_MAX); + std::fill_n(mReserved, sizeof(mReserved)/sizeof(mReserved[0]), UINT8_MAX); } PageState mState; // page state uint32_t mSeqNumber; // sequence number of this page - uint32_t mReserved[5]; // unused, must be 0xffffffff + uint8_t mVersion; // nvs format version + uint8_t mReserved[19]; // unused, must be 0xff uint32_t mCrc32; // crc of everything except mState uint32_t calculateCrc32(); @@ -171,7 +191,7 @@ class Page : public intrusive_list_node esp_err_t readEntry(size_t index, Item& dst) const; esp_err_t writeEntry(const Item& item); - + esp_err_t writeEntryData(const uint8_t* data, size_t size); esp_err_t eraseEntryAndSpan(size_t index); @@ -188,7 +208,7 @@ class Page : public intrusive_list_node assert(entry < ENTRY_COUNT); return mBaseAddress + ENTRY_DATA_OFFSET + static_cast(entry) * ENTRY_SIZE; } - + static const char* pageStateToName(PageState ps); @@ -196,6 +216,7 @@ class Page : public intrusive_list_node uint32_t mBaseAddress = 0; PageState mState = PageState::INVALID; uint32_t mSeqNumber = UINT32_MAX; + uint8_t mVersion = NVS_VERSION; typedef CompressedEnumTable TEntryTable; TEntryTable mEntryTable; size_t mNextFreeEntry = INVALID_ENTRY; @@ -203,8 +224,13 @@ class Page : public intrusive_list_node uint16_t mUsedEntryCount = 0; uint16_t mErasedEntryCount = 0; + /** + * This hash list stores hashes of namespace index, key, and ChunkIndex for quick lookup when searching items. + */ HashList mHashList; + Partition *mPartition; + static const uint32_t HEADER_OFFSET = 0; static const uint32_t ENTRY_TABLE_OFFSET = HEADER_OFFSET + 32; static const uint32_t ENTRY_DATA_OFFSET = ENTRY_TABLE_OFFSET + 32; diff --git a/components/nvs_flash/src/nvs_pagemanager.cpp b/components/nvs_flash/src/nvs_pagemanager.cpp index 31240d98b..88a830bd0 100644 --- a/components/nvs_flash/src/nvs_pagemanager.cpp +++ b/components/nvs_flash/src/nvs_pagemanager.cpp @@ -15,16 +15,22 @@ namespace nvs { -esp_err_t PageManager::load(uint32_t baseSector, uint32_t sectorCount) +esp_err_t PageManager::load(Partition *partition, uint32_t baseSector, uint32_t sectorCount) { + if (partition == nullptr) { + return ESP_ERR_INVALID_ARG; + } + mBaseSector = baseSector; mPageCount = sectorCount; mPageList.clear(); mFreePageList.clear(); - mPages.reset(new Page[sectorCount]); + mPages.reset(new (nothrow) Page[sectorCount]); + + if (!mPages) return ESP_ERR_NO_MEM; for (uint32_t i = 0; i < sectorCount; ++i) { - auto err = mPages[i].load(baseSector + i); + auto err = mPages[i].load(partition, baseSector + i); if (err != ESP_OK) { return err; } @@ -66,13 +72,26 @@ esp_err_t PageManager::load(uint32_t baseSector, uint32_t sectorCount) if (lastItemIndex != SIZE_MAX) { auto last = PageManager::TPageListIterator(&lastPage); - for (auto it = begin(); it != last; ++it) { + TPageListIterator it; + + for (it = begin(); it != last; ++it) { if ((it->state() != Page::PageState::FREEING) && - (it->eraseItem(item.nsIndex, item.datatype, item.key) == ESP_OK)) { + (it->eraseItem(item.nsIndex, item.datatype, item.key, item.chunkIndex) == ESP_OK)) { break; } } + if ((it == last) && (item.datatype == ItemType::BLOB_IDX)) { + /* Rare case in which the blob was stored using old format, but power went just after writing + * blob index during modification. Loop again and delete the old version blob*/ + for (it = begin(); it != last; ++it) { + + if ((it->state() != Page::PageState::FREEING) && + (it->eraseItem(item.nsIndex, ItemType::BLOB, item.key, item.chunkIndex) == ESP_OK)) { + break; + } + } + } } // check if power went out while page was being freed @@ -111,7 +130,7 @@ esp_err_t PageManager::load(uint32_t baseSector, uint32_t sectorCount) } // partition should have at least one free page - if (mFreePageList.size() == 0) { + if (mFreePageList.empty()) { return ESP_ERR_NVS_NO_FREE_PAGES; } @@ -200,4 +219,26 @@ esp_err_t PageManager::activatePage() return ESP_OK; } +esp_err_t PageManager::fillStats(nvs_stats_t& nvsStats) +{ + nvsStats.used_entries = 0; + nvsStats.free_entries = 0; + nvsStats.total_entries = 0; + esp_err_t err = ESP_OK; + + // list of used pages + for (auto p = mPageList.begin(); p != mPageList.end(); ++p) { + err = p->calcEntries(nvsStats); + if (err != ESP_OK) { + return err; + } + } + + // free pages + nvsStats.total_entries += mFreePageList.size() * Page::ENTRY_COUNT; + nvsStats.free_entries += mFreePageList.size() * Page::ENTRY_COUNT; + + return err; +} + } // namespace nvs diff --git a/components/nvs_flash/src/nvs_pagemanager.hpp b/components/nvs_flash/src/nvs_pagemanager.hpp index 10c545f0f..4a1c19f7e 100644 --- a/components/nvs_flash/src/nvs_pagemanager.hpp +++ b/components/nvs_flash/src/nvs_pagemanager.hpp @@ -18,7 +18,7 @@ #include #include "nvs_types.hpp" #include "nvs_page.hpp" -#include "nvs_pagemanager.hpp" +#include "partition.hpp" #include "intrusive_list.h" namespace nvs @@ -31,7 +31,7 @@ class PageManager PageManager() {} - esp_err_t load(uint32_t baseSector, uint32_t sectorCount); + esp_err_t load(Partition *partition, uint32_t baseSector, uint32_t sectorCount); TPageListIterator begin() { @@ -48,8 +48,19 @@ class PageManager return mPageList.back(); } + uint32_t getPageCount() { + return mPageCount; + } + esp_err_t requestNewPage(); + esp_err_t fillStats(nvs_stats_t& nvsStats); + + uint32_t getBaseSector() + { + return mBaseSector; + } + protected: friend class Iterator; diff --git a/components/nvs_flash/src/nvs_partition.cpp b/components/nvs_flash/src/nvs_partition.cpp new file mode 100644 index 000000000..f1b7d36d2 --- /dev/null +++ b/components/nvs_flash/src/nvs_partition.cpp @@ -0,0 +1,77 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "nvs_partition.hpp" + +namespace nvs { + +NVSPartition::NVSPartition(const esp_partition_t* partition) + : mESPPartition(partition) +{ + // ensure the class is in a valid state + if (partition == nullptr) { + std::abort(); + } +} + +const char *NVSPartition::get_partition_name() +{ + return mESPPartition->label; +} + +esp_err_t NVSPartition::read_raw(size_t src_offset, void* dst, size_t size) +{ + return esp_partition_read_raw(mESPPartition, src_offset, dst, size); +} + +esp_err_t NVSPartition::read(size_t src_offset, void* dst, size_t size) +{ + if (size % ESP_ENCRYPT_BLOCK_SIZE != 0) { + return ESP_ERR_INVALID_ARG; + } + + return esp_partition_read(mESPPartition, src_offset, dst, size); +} + +esp_err_t NVSPartition::write_raw(size_t dst_offset, const void* src, size_t size) +{ + return esp_partition_write_raw(mESPPartition, dst_offset, src, size); +} + +esp_err_t NVSPartition::write(size_t dst_offset, const void* src, size_t size) +{ + if (size % ESP_ENCRYPT_BLOCK_SIZE != 0) { + return ESP_ERR_INVALID_ARG; + } + + return esp_partition_write(mESPPartition, dst_offset, src, size); +} + +esp_err_t NVSPartition::erase_range(size_t dst_offset, size_t size) +{ + return esp_partition_erase_range(mESPPartition, dst_offset, size); +} + +uint32_t NVSPartition::get_address() +{ + return mESPPartition->address; +} + +uint32_t NVSPartition::get_size() +{ + return mESPPartition->size; +} + +} // nvs diff --git a/components/nvs_flash/src/nvs_partition.hpp b/components/nvs_flash/src/nvs_partition.hpp new file mode 100644 index 000000000..2af3e238e --- /dev/null +++ b/components/nvs_flash/src/nvs_partition.hpp @@ -0,0 +1,115 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ESP_PARTITION_HPP_ +#define ESP_PARTITION_HPP_ + +#include "esp_partition.h" +#include "intrusive_list.h" +#include "partition.hpp" + +#define ESP_ENCRYPT_BLOCK_SIZE 16 + +#define PART_NAME_MAX_SIZE 16 /*!< maximum length of partition name (excluding null terminator) */ + +namespace nvs { + +/** + * Implementation of Partition for NVS. + * + * It is implemented as an intrusive_list_node to easily store instances of it. NVSStorage and NVSPage take pointer + * references of this class to abstract their partition operations. + */ +class NVSPartition : public Partition, public intrusive_list_node { +public: + /** + * Copy partition_name to mPartitionName and initialize mESPPartition. + * + * @param partition_name the name of the partition as in the partition table, must be non-NULL! + * @param partition an already initialized partition structure + */ + NVSPartition(const esp_partition_t* partition); + + /** + * No need to de-initialize mESPPartition here, if you used esp_partition_find_first. + * Otherwise, the user is responsible for de-initializing it. + */ + virtual ~NVSPartition() { } + + const char *get_partition_name() override; + + /** + * Look into \c esp_partition_read_raw for more details. + * + * @return + * - ESP_OK on success + * - other error codes from the esp_partition API + */ + esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override; + + /** + * Look into \c esp_partition_read for more details. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if size isn't a multiple of ESP_ENCRYPT_BLOCK_SIZE + * - other error codes from the esp_partition API + */ + esp_err_t read(size_t src_offset, void* dst, size_t size) override; + + /** + * Look into \c esp_partition_write_raw for more details. + * + * @return + * - ESP_OK on success + * - error codes from the esp_partition API + */ + esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override; + + /** + * Look into \c esp_partition_write for more details. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if size isn't a multiple of ESP_ENCRYPT_BLOCK_SIZE + * - other error codes from the esp_partition API + */ + esp_err_t write(size_t dst_offset, const void* src, size_t size) override; + + /** + * Look into \c esp_partition_erase_range for more details. + * + * @return + * - ESP_OK on success + * - error codes from the esp_partition API + */ + esp_err_t erase_range(size_t dst_offset, size_t size) override; + + /** + * @return the base address of the partition. + */ + uint32_t get_address() override; + + /** + * @return the size of the partition in bytes. + */ + uint32_t get_size() override; + +protected: + const esp_partition_t* mESPPartition; +}; + +} // nvs + +#endif // ESP_PARTITION_HPP_ diff --git a/components/nvs_flash/src/nvs_partition_lookup.cpp b/components/nvs_flash/src/nvs_partition_lookup.cpp new file mode 100644 index 000000000..e9d27256f --- /dev/null +++ b/components/nvs_flash/src/nvs_partition_lookup.cpp @@ -0,0 +1,69 @@ +#include "esp_partition.h" +#include "nvs_partition_lookup.hpp" + +#ifdef CONFIG_NVS_ENCRYPTION +#include "nvs_encrypted_partition.hpp" +#endif // CONFIG_NVS_ENCRYPTION + +namespace nvs { + +namespace partition_lookup { + +esp_err_t lookup_nvs_partition(const char* label, NVSPartition **p) +{ + const esp_partition_t* esp_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, label); + + if (esp_partition == nullptr) { + return ESP_ERR_NOT_FOUND; + } + + if (esp_partition->encrypted) { + return ESP_ERR_NVS_WRONG_ENCRYPTION; + } + + NVSPartition *partition = new (std::nothrow) NVSPartition(esp_partition); + if (partition == nullptr) { + return ESP_ERR_NO_MEM; + } + + *p = partition; + + return ESP_OK; +} + +#ifdef CONFIG_NVS_ENCRYPTION +esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, NVSPartition **p) +{ + const esp_partition_t* esp_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, label); + + if (esp_partition == nullptr) { + return ESP_ERR_NOT_FOUND; + } + + if (esp_partition->encrypted) { + return ESP_ERR_NVS_WRONG_ENCRYPTION; + } + + NVSEncryptedPartition *enc_p = new (std::nothrow) NVSEncryptedPartition(esp_partition); + if (enc_p == nullptr) { + return ESP_ERR_NO_MEM; + } + + esp_err_t result = enc_p->init(cfg); + if (result != ESP_OK) { + delete enc_p; + return result; + } + + *p = enc_p; + + return ESP_OK; +} + +#endif // CONFIG_NVS_ENCRYPTION + +} // partition_lookup + +} // nvs diff --git a/components/nvs_flash/src/nvs_partition_lookup.hpp b/components/nvs_flash/src/nvs_partition_lookup.hpp new file mode 100644 index 000000000..62a8e8b6f --- /dev/null +++ b/components/nvs_flash/src/nvs_partition_lookup.hpp @@ -0,0 +1,22 @@ +#include "esp_err.h" +#include "nvs_partition.hpp" +#include "nvs_flash.h" + +#ifndef NVS_PARTITION_LOOKUP_HPP_ +#define NVS_PARTITION_LOOKUP_HPP_ + +namespace nvs { + +namespace partition_lookup { + +esp_err_t lookup_nvs_partition(const char* label, NVSPartition **p); + +#ifdef CONFIG_NVS_ENCRYPTION +esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, NVSPartition **p); +#endif // CONFIG_NVS_ENCRYPTION + +} // partition_lookup + +} // nvs + +#endif // NVS_PARTITION_LOOKUP_HPP_ diff --git a/components/nvs_flash/src/nvs_partition_manager.cpp b/components/nvs_flash/src/nvs_partition_manager.cpp new file mode 100644 index 000000000..b95db7e81 --- /dev/null +++ b/components/nvs_flash/src/nvs_partition_manager.cpp @@ -0,0 +1,244 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "esp_partition.h" +#include "nvs_partition_manager.hpp" +#include "nvs_partition_lookup.hpp" + +#ifdef CONFIG_NVS_ENCRYPTION +#include "nvs_encrypted_partition.hpp" +#endif // CONFIG_NVS_ENCRYPTION + +namespace nvs { + +NVSPartitionManager* NVSPartitionManager::instance = nullptr; + +NVSPartitionManager* NVSPartitionManager::get_instance() +{ + if (!instance) { + instance = new (std::nothrow) NVSPartitionManager(); + } + + return instance; +} + +#ifdef ESP_PLATFORM +esp_err_t NVSPartitionManager::init_partition(const char *partition_label) +{ + if (strlen(partition_label) > NVS_PART_NAME_MAX_SIZE) { + return ESP_ERR_INVALID_ARG; + } + + uint32_t size; + Storage* mStorage; + + mStorage = lookup_storage_from_name(partition_label); + if (mStorage) { + return ESP_OK; + } + + assert(SPI_FLASH_SEC_SIZE != 0); + + NVSPartition *p = nullptr; + esp_err_t result = partition_lookup::lookup_nvs_partition(partition_label, &p); + + if (result != ESP_OK) { + goto error; + } + + size = p->get_size(); + + result = init_custom(p, 0, size / SPI_FLASH_SEC_SIZE); + if (result != ESP_OK) { + goto error; + } + + nvs_partition_list.push_back(p); + + return ESP_OK; + +error: + delete p; + return result; +} +#endif // ESP_PLATFORM + +esp_err_t NVSPartitionManager::init_custom(Partition *partition, uint32_t baseSector, uint32_t sectorCount) +{ + Storage* new_storage = nullptr; + Storage* storage = lookup_storage_from_name(partition->get_partition_name()); + if (storage == nullptr) { + new_storage = new (std::nothrow) Storage(partition); + + if (new_storage == nullptr) { + return ESP_ERR_NO_MEM; + } + + storage = new_storage; + } else { + // if storage was initialized already, we don't need partition and hence delete it + for (auto it = nvs_partition_list.begin(); it != nvs_partition_list.end(); ++it) { + if (partition == it) { + nvs_partition_list.erase(it); + delete partition; + break; + } + } + } + + esp_err_t err = storage->init(baseSector, sectorCount); + if (new_storage != nullptr) { + if (err == ESP_OK) { + nvs_storage_list.push_back(new_storage); + } else { + delete new_storage; + } + } + return err; +} + +#ifdef CONFIG_NVS_ENCRYPTION +#ifdef ESP_PLATFORM +esp_err_t NVSPartitionManager::secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg) +{ + if (strlen(part_name) > NVS_PART_NAME_MAX_SIZE) { + return ESP_ERR_INVALID_ARG; + } + + Storage* mStorage; + + mStorage = lookup_storage_from_name(part_name); + if (mStorage != nullptr) { + return ESP_OK; + } + + NVSPartition *p; + esp_err_t result; + if (cfg != nullptr) { + result = partition_lookup::lookup_nvs_encrypted_partition(part_name, cfg, &p); + } else { + result = partition_lookup::lookup_nvs_partition(part_name, &p); + } + + if (result != ESP_OK) { + return result; + } + + uint32_t size = p->get_size(); + + result = init_custom(p, 0, size / SPI_FLASH_SEC_SIZE); + if (result != ESP_OK) { + delete p; + return result; + } + + nvs_partition_list.push_back(p); + + return ESP_OK; +} +#endif // ESP_PLATFORM +#endif // CONFIG_NVS_ENCRYPTION + +esp_err_t NVSPartitionManager::deinit_partition(const char *partition_label) +{ + Storage* storage = lookup_storage_from_name(partition_label); + if (!storage) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + /* Clean up handles related to the storage being deinitialized */ + for (auto it = nvs_handles.begin(); it != nvs_handles.end(); ++it) { + if (it->mStoragePtr == storage) { + it->valid = false; + nvs_handles.erase(it); + } + } + + /* Finally delete the storage and its partition */ + nvs_storage_list.erase(storage); + delete storage; + + for (auto it = nvs_partition_list.begin(); it != nvs_partition_list.end(); ++it) { + if (strcmp(it->get_partition_name(), partition_label) == 0) { + NVSPartition *p = it; + nvs_partition_list.erase(it); + delete p; + break; + } + } + + return ESP_OK; +} + +esp_err_t NVSPartitionManager::open_handle(const char *part_name, + const char *ns_name, + nvs_open_mode_t open_mode, + NVSHandleSimple** handle) +{ + uint8_t nsIndex; + Storage* sHandle; + + if (nvs_storage_list.empty()) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + sHandle = lookup_storage_from_name(part_name); + if (sHandle == nullptr) { + return ESP_ERR_NVS_PART_NOT_FOUND; + } + + esp_err_t err = sHandle->createOrOpenNamespace(ns_name, open_mode == NVS_READWRITE, nsIndex); + if (err != ESP_OK) { + return err; + } + + *handle = new (std::nothrow) NVSHandleSimple(open_mode==NVS_READONLY, nsIndex, sHandle); + + if (handle == nullptr) { + return ESP_ERR_NO_MEM; + } + + nvs_handles.push_back(*handle); + + return ESP_OK; +} + +esp_err_t NVSPartitionManager::close_handle(NVSHandleSimple* handle) { + for (auto it = nvs_handles.begin(); it != nvs_handles.end(); ++it) { + if (it == intrusive_list::iterator(handle)) { + nvs_handles.erase(it); + return ESP_OK; + } + } + + return ESP_ERR_NVS_INVALID_HANDLE; +} + +size_t NVSPartitionManager::open_handles_size() +{ + return nvs_handles.size(); +} + +Storage* NVSPartitionManager::lookup_storage_from_name(const char* name) +{ + auto it = find_if(begin(nvs_storage_list), end(nvs_storage_list), [=](Storage& e) -> bool { + return (strcmp(e.getPartName(), name) == 0); + }); + + if (it == end(nvs_storage_list)) { + return nullptr; + } + return it; +} + +} // nvs diff --git a/components/nvs_flash/src/nvs_partition_manager.hpp b/components/nvs_flash/src/nvs_partition_manager.hpp new file mode 100644 index 000000000..885787de4 --- /dev/null +++ b/components/nvs_flash/src/nvs_partition_manager.hpp @@ -0,0 +1,62 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef NVS_PARTITION_MANAGER_HPP_ +#define NVS_PARTITION_MANAGER_HPP_ + +#include "nvs_handle_simple.hpp" +#include "nvs_storage.hpp" +#include "nvs_partition.hpp" +#include "nvs_flash.h" + +namespace nvs { + +class NVSPartitionManager { +public: + virtual ~NVSPartitionManager() { } + + static NVSPartitionManager* get_instance(); + + esp_err_t init_partition(const char *partition_label); + + esp_err_t init_custom(Partition *partition, uint32_t baseSector, uint32_t sectorCount); + +#ifdef CONFIG_NVS_ENCRYPTION + esp_err_t secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg); +#endif + + esp_err_t deinit_partition(const char *partition_label); + + Storage* lookup_storage_from_name(const char* name); + + esp_err_t open_handle(const char *part_name, const char *ns_name, nvs_open_mode_t open_mode, NVSHandleSimple** handle); + + esp_err_t close_handle(NVSHandleSimple* handle); + + size_t open_handles_size(); + +protected: + NVSPartitionManager() { } + + static NVSPartitionManager* instance; + + intrusive_list nvs_handles; + + intrusive_list nvs_storage_list; + + intrusive_list nvs_partition_list; +}; + +} // nvs + +#endif // NVS_PARTITION_MANAGER_HPP_ diff --git a/components/nvs_flash/src/nvs_platform.hpp b/components/nvs_flash/src/nvs_platform.hpp index 0973c4875..5c6b5b8b2 100644 --- a/components/nvs_flash/src/nvs_platform.hpp +++ b/components/nvs_flash/src/nvs_platform.hpp @@ -11,11 +11,23 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#ifndef nvs_platform_h -#define nvs_platform_h +#pragma once +#ifdef LINUX_TARGET +namespace nvs +{ +class Lock +{ +public: + Lock() { } + ~Lock() { } + static void init() {} + static void uninit() {} +}; +} // namespace nvs + +#else // LINUX_TARGET -#ifdef ESP_PLATFORM #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" @@ -63,19 +75,4 @@ class Lock }; } // namespace nvs -#else // ESP_PLATFORM -namespace nvs -{ -class Lock -{ -public: - Lock() { } - ~Lock() { } - static void init() {} - static void uninit() {} -}; -} // namespace nvs -#endif // ESP_PLATFORM - - -#endif /* nvs_platform_h */ +#endif // LINUX_TARGET diff --git a/components/nvs_flash/src/nvs_storage.cpp b/components/nvs_flash/src/nvs_storage.cpp index f8da28fa2..52952b7a3 100644 --- a/components/nvs_flash/src/nvs_storage.cpp +++ b/components/nvs_flash/src/nvs_storage.cpp @@ -14,9 +14,15 @@ #include "nvs_storage.hpp" #ifndef ESP_PLATFORM +// We need NO_DEBUG_STORAGE here since the integration tests on the host add some debug code. +// The unit tests, however, don't want debug code since they check the behavior via data in/output and disturb +// the order of calling mocked functions. +#ifndef NO_DEBUG_STORAGE #include #include +#define DEBUG_STORAGE #endif +#endif // !ESP_PLATFORM namespace nvs { @@ -28,17 +34,69 @@ Storage::~Storage() void Storage::clearNamespaces() { - for (auto it = std::begin(mNamespaces); it != std::end(mNamespaces); ) { - auto tmp = it; - ++it; - mNamespaces.erase(tmp); - delete static_cast(tmp); + mNamespaces.clearAndFreeNodes(); +} + +esp_err_t Storage::populateBlobIndices(TBlobIndexList& blobIdxList) +{ + for (auto it = mPageManager.begin(); it != mPageManager.end(); ++it) { + Page& p = *it; + size_t itemIndex = 0; + Item item; + + /* If the power went off just after writing a blob index, the duplicate detection + * logic in pagemanager will remove the earlier index. So we should never find a + * duplicate index at this point */ + + while (p.findItem(Page::NS_ANY, ItemType::BLOB_IDX, nullptr, itemIndex, item) == ESP_OK) { + BlobIndexNode* entry = new (std::nothrow) BlobIndexNode; + + if (!entry) return ESP_ERR_NO_MEM; + + item.getKey(entry->key, sizeof(entry->key)); + entry->nsIndex = item.nsIndex; + entry->chunkStart = item.blobIndex.chunkStart; + entry->chunkCount = item.blobIndex.chunkCount; + + blobIdxList.push_back(entry); + itemIndex += item.span; + } + } + + return ESP_OK; +} + +void Storage::eraseOrphanDataBlobs(TBlobIndexList& blobIdxList) +{ + for (auto it = mPageManager.begin(); it != mPageManager.end(); ++it) { + Page& p = *it; + size_t itemIndex = 0; + Item item; + /* Chunks with same and with chunkIndex in the following ranges + * belong to same family. + * 1) VER_0_OFFSET <= chunkIndex < VER_1_OFFSET-1 => Version0 chunks + * 2) VER_1_OFFSET <= chunkIndex < VER_ANY => Version1 chunks + */ + while (p.findItem(Page::NS_ANY, ItemType::BLOB_DATA, nullptr, itemIndex, item) == ESP_OK) { + + auto iter = std::find_if(blobIdxList.begin(), + blobIdxList.end(), + [=] (const BlobIndexNode& e) -> bool + {return (strncmp(item.key, e.key, sizeof(e.key) - 1) == 0) + && (item.nsIndex == e.nsIndex) + && (item.chunkIndex >= static_cast (e.chunkStart)) + && (item.chunkIndex < static_cast (e.chunkStart) + e.chunkCount);}); + if (iter == std::end(blobIdxList)) { + p.eraseItem(item.nsIndex, item.datatype, item.key, item.chunkIndex); + } + itemIndex += item.span; + } } } esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount) { - auto err = mPageManager.load(baseSector, sectorCount); + auto err = mPageManager.load(mPartition, baseSector, sectorCount); if (err != ESP_OK) { mState = StorageState::INVALID; return err; @@ -52,8 +110,14 @@ esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount) size_t itemIndex = 0; Item item; while (p.findItem(Page::NS_INDEX, ItemType::U8, nullptr, itemIndex, item) == ESP_OK) { - NamespaceEntry* entry = new NamespaceEntry; - item.getKey(entry->mName, sizeof(entry->mName) - 1); + NamespaceEntry* entry = new (std::nothrow) NamespaceEntry; + + if (!entry) { + mState = StorageState::INVALID; + return ESP_ERR_NO_MEM; + } + + item.getKey(entry->mName, sizeof(entry->mName)); item.getValue(entry->mIndex); mNamespaces.push_back(entry); mNamespaceUsage.set(entry->mIndex, true); @@ -63,7 +127,22 @@ esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount) mNamespaceUsage.set(0, true); mNamespaceUsage.set(255, true); mState = StorageState::ACTIVE; -#ifndef ESP_PLATFORM + + // Populate list of multi-page index entries. + TBlobIndexList blobIdxList; + err = populateBlobIndices(blobIdxList); + if (err != ESP_OK) { + mState = StorageState::INVALID; + return ESP_ERR_NO_MEM; + } + + // Remove the entries for which there is no parent multi-page index. + eraseOrphanDataBlobs(blobIdxList); + + // Purge the blob index list + blobIdxList.clearAndFreeNodes(); + +#ifdef DEBUG_STORAGE debugCheck(); #endif return ESP_OK; @@ -74,11 +153,11 @@ bool Storage::isValid() const return mState == StorageState::ACTIVE; } -esp_err_t Storage::findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item) +esp_err_t Storage::findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item, uint8_t chunkIdx, VerOffset chunkStart) { for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) { size_t itemIndex = 0; - auto err = it->findItem(nsIndex, datatype, key, itemIndex, item); + auto err = it->findItem(nsIndex, datatype, key, itemIndex, item, chunkIdx, chunkStart); if (err == ESP_OK) { page = it; return ESP_OK; @@ -87,6 +166,109 @@ esp_err_t Storage::findItem(uint8_t nsIndex, ItemType datatype, const char* key, return ESP_ERR_NVS_NOT_FOUND; } +esp_err_t Storage::writeMultiPageBlob(uint8_t nsIndex, const char* key, const void* data, size_t dataSize, VerOffset chunkStart) +{ + uint8_t chunkCount = 0; + TUsedPageList usedPages; + size_t remainingSize = dataSize; + size_t offset = 0; + esp_err_t err = ESP_OK; + + /* Check how much maximum data can be accommodated**/ + uint32_t max_pages = mPageManager.getPageCount() - 1; + + if(max_pages > (Page::CHUNK_ANY-1)/2) { + max_pages = (Page::CHUNK_ANY-1)/2; + } + + if (dataSize > max_pages * Page::CHUNK_MAX_SIZE) { + return ESP_ERR_NVS_VALUE_TOO_LONG; + } + + do { + Page& page = getCurrentPage(); + size_t tailroom = page.getVarDataTailroom(); + size_t chunkSize = 0; + if (chunkCount == 0U && ((tailroom < dataSize) || (tailroom == 0 && dataSize == 0)) && tailroom < Page::CHUNK_MAX_SIZE/10) { + /** This is the first chunk and tailroom is too small ***/ + if (page.state() != Page::PageState::FULL) { + err = page.markFull(); + if (err != ESP_OK) { + return err; + } + } + err = mPageManager.requestNewPage(); + if (err != ESP_OK) { + return err; + } else if(getCurrentPage().getVarDataTailroom() == tailroom) { + /* We got the same page or we are not improving.*/ + return ESP_ERR_NVS_NOT_ENOUGH_SPACE; + } else { + continue; + } + } else if (!tailroom) { + err = ESP_ERR_NVS_NOT_ENOUGH_SPACE; + break; + } + + /* Split the blob into two and store the chunk of available size onto the current page */ + assert(tailroom != 0); + chunkSize = (remainingSize > tailroom)? tailroom : remainingSize; + remainingSize -= chunkSize; + + err = page.writeItem(nsIndex, ItemType::BLOB_DATA, key, + static_cast (data) + offset, chunkSize, static_cast (chunkStart) + chunkCount); + chunkCount++; + assert(err != ESP_ERR_NVS_PAGE_FULL); + if (err != ESP_OK) { + break; + } else { + UsedPageNode* node = new (std::nothrow) UsedPageNode(); + if (!node) { + err = ESP_ERR_NO_MEM; + break; + } + node->mPage = &page; + usedPages.push_back(node); + if (remainingSize || (tailroom - chunkSize) < Page::ENTRY_SIZE) { + if (page.state() != Page::PageState::FULL) { + err = page.markFull(); + if (err != ESP_OK) { + break; + } + } + err = mPageManager.requestNewPage(); + if (err != ESP_OK) { + break; + } + } + } + offset += chunkSize; + if (!remainingSize) { + /* All pages are stored. Now store the index.*/ + Item item; + std::fill_n(item.data, sizeof(item.data), 0xff); + item.blobIndex.dataSize = dataSize; + item.blobIndex.chunkCount = chunkCount; + item.blobIndex.chunkStart = chunkStart; + + err = getCurrentPage().writeItem(nsIndex, ItemType::BLOB_IDX, key, item.data, sizeof(item.data)); + assert(err != ESP_ERR_NVS_PAGE_FULL); + break; + } + } while (1); + + if (err != ESP_OK) { + /* Anything failed, then we should erase all the written chunks*/ + int ii=0; + for (auto it = std::begin(usedPages); it != std::end(usedPages); it++) { + it->mPage->eraseItem(nsIndex, ItemType::BLOB_DATA, key, ii++); + } + } + usedPages.clearAndFreeNodes(); + return err; +} + esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize) { if (mState != StorageState::ACTIVE) { @@ -95,40 +277,109 @@ esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key Page* findPage = nullptr; Item item; - auto err = findItem(nsIndex, datatype, key, findPage, item); + + esp_err_t err; + if (datatype == ItemType::BLOB) { + err = findItem(nsIndex, ItemType::BLOB_IDX, key, findPage, item); + } else { + err = findItem(nsIndex, datatype, key, findPage, item); + } + if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) { return err; } - Page& page = getCurrentPage(); - err = page.writeItem(nsIndex, datatype, key, data, dataSize); - if (err == ESP_ERR_NVS_PAGE_FULL) { - if (page.state() != Page::PageState::FULL) { - err = page.markFull(); - if (err != ESP_OK) { - return err; + if (datatype == ItemType::BLOB) { + VerOffset prevStart, nextStart; + prevStart = nextStart = VerOffset::VER_0_OFFSET; + if (findPage) { + // Do a sanity check that the item in question is actually being modified. + // If it isn't, it is cheaper to purposefully not write out new data. + // since it may invoke an erasure of flash. + if (cmpMultiPageBlob(nsIndex, key, data, dataSize) == ESP_OK) { + return ESP_OK; } + + if (findPage->state() == Page::PageState::UNINITIALIZED || + findPage->state() == Page::PageState::INVALID) { + ESP_ERROR_CHECK(findItem(nsIndex, datatype, key, findPage, item)); + } + /* Get the version of the previous index with same */ + prevStart = item.blobIndex.chunkStart; + assert(prevStart == VerOffset::VER_0_OFFSET || prevStart == VerOffset::VER_1_OFFSET); + + /* Toggle the version by changing the offset */ + nextStart + = (prevStart == VerOffset::VER_1_OFFSET) ? VerOffset::VER_0_OFFSET : VerOffset::VER_1_OFFSET; } - err = mPageManager.requestNewPage(); - if (err != ESP_OK) { - return err; - } + /* Write the blob with new version*/ + err = writeMultiPageBlob(nsIndex, key, data, dataSize, nextStart); - err = getCurrentPage().writeItem(nsIndex, datatype, key, data, dataSize); if (err == ESP_ERR_NVS_PAGE_FULL) { return ESP_ERR_NVS_NOT_ENOUGH_SPACE; } if (err != ESP_OK) { return err; } - } else if (err != ESP_OK) { - return err; + + if (findPage) { + /* Erase the blob with earlier version*/ + err = eraseMultiPageBlob(nsIndex, key, prevStart); + + if (err == ESP_ERR_FLASH_OP_FAIL) { + return ESP_ERR_NVS_REMOVE_FAILED; + } + if (err != ESP_OK) { + return err; + } + + findPage = nullptr; + } else { + /* Support for earlier versions where BLOBS were stored without index */ + err = findItem(nsIndex, datatype, key, findPage, item); + if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) { + return err; + } + } + } else { + // Do a sanity check that the item in question is actually being modified. + // If it isn't, it is cheaper to purposefully not write out new data. + // since it may invoke an erasure of flash. + if (findPage != nullptr && + findPage->cmpItem(nsIndex, datatype, key, data, dataSize) == ESP_OK) { + return ESP_OK; + } + + Page& page = getCurrentPage(); + err = page.writeItem(nsIndex, datatype, key, data, dataSize); + if (err == ESP_ERR_NVS_PAGE_FULL) { + if (page.state() != Page::PageState::FULL) { + err = page.markFull(); + if (err != ESP_OK) { + return err; + } + } + err = mPageManager.requestNewPage(); + if (err != ESP_OK) { + return err; + } + + err = getCurrentPage().writeItem(nsIndex, datatype, key, data, dataSize); + if (err == ESP_ERR_NVS_PAGE_FULL) { + return ESP_ERR_NVS_NOT_ENOUGH_SPACE; + } + if (err != ESP_OK) { + return err; + } + } else if (err != ESP_OK) { + return err; + } } if (findPage) { if (findPage->state() == Page::PageState::UNINITIALIZED || findPage->state() == Page::PageState::INVALID) { - ESP_ERROR_CHECK( findItem(nsIndex, datatype, key, findPage, item) ); + ESP_ERROR_CHECK(findItem(nsIndex, datatype, key, findPage, item)); } err = findPage->eraseItem(nsIndex, datatype, key); if (err == ESP_ERR_FLASH_OP_FAIL) { @@ -138,7 +389,7 @@ esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key return err; } } -#ifndef ESP_PLATFORM +#ifdef DEBUG_STORAGE debugCheck(); #endif return ESP_OK; @@ -168,6 +419,11 @@ esp_err_t Storage::createOrOpenNamespace(const char* nsName, bool canCreate, uin return ESP_ERR_NVS_NOT_ENOUGH_SPACE; } + NamespaceEntry* entry = new (std::nothrow) NamespaceEntry; + if (!entry) { + return ESP_ERR_NO_MEM; + } + auto err = writeItem(Page::NS_INDEX, ItemType::U8, nsName, &ns, sizeof(ns)); if (err != ESP_OK) { return err; @@ -175,7 +431,6 @@ esp_err_t Storage::createOrOpenNamespace(const char* nsName, bool canCreate, uin mNamespaceUsage.set(ns, true); nsIndex = ns; - NamespaceEntry* entry = new NamespaceEntry; entry->mIndex = ns; strncpy(entry->mName, nsName, sizeof(entry->mName) - 1); entry->mName[sizeof(entry->mName) - 1] = 0; @@ -187,6 +442,91 @@ esp_err_t Storage::createOrOpenNamespace(const char* nsName, bool canCreate, uin return ESP_OK; } +esp_err_t Storage::readMultiPageBlob(uint8_t nsIndex, const char* key, void* data, size_t dataSize) +{ + Item item; + Page* findPage = nullptr; + + /* First read the blob index */ + auto err = findItem(nsIndex, ItemType::BLOB_IDX, key, findPage, item); + if (err != ESP_OK) { + return err; + } + + uint8_t chunkCount = item.blobIndex.chunkCount; + VerOffset chunkStart = item.blobIndex.chunkStart; + size_t readSize = item.blobIndex.dataSize; + size_t offset = 0; + + assert(dataSize == readSize); + + /* Now read corresponding chunks */ + for (uint8_t chunkNum = 0; chunkNum < chunkCount; chunkNum++) { + err = findItem(nsIndex, ItemType::BLOB_DATA, key, findPage, item, static_cast (chunkStart) + chunkNum); + if (err != ESP_OK) { + if (err == ESP_ERR_NVS_NOT_FOUND) { + break; + } + return err; + } + err = findPage->readItem(nsIndex, ItemType::BLOB_DATA, key, static_cast(data) + offset, item.varLength.dataSize, static_cast (chunkStart) + chunkNum); + if (err != ESP_OK) { + return err; + } + assert(static_cast (chunkStart) + chunkNum == item.chunkIndex); + offset += item.varLength.dataSize; + } + if (err == ESP_OK) { + assert(offset == dataSize); + } + if (err == ESP_ERR_NVS_NOT_FOUND) { + eraseMultiPageBlob(nsIndex, key); // cleanup if a chunk is not found + } + return err; +} + +esp_err_t Storage::cmpMultiPageBlob(uint8_t nsIndex, const char* key, const void* data, size_t dataSize) +{ + Item item; + Page* findPage = nullptr; + + /* First read the blob index */ + auto err = findItem(nsIndex, ItemType::BLOB_IDX, key, findPage, item); + if (err != ESP_OK) { + return err; + } + + uint8_t chunkCount = item.blobIndex.chunkCount; + VerOffset chunkStart = item.blobIndex.chunkStart; + size_t readSize = item.blobIndex.dataSize; + size_t offset = 0; + + if (dataSize != readSize) { + return ESP_ERR_NVS_CONTENT_DIFFERS; + } + + /* Now read corresponding chunks */ + for (uint8_t chunkNum = 0; chunkNum < chunkCount; chunkNum++) { + err = findItem(nsIndex, ItemType::BLOB_DATA, key, findPage, item, static_cast (chunkStart) + chunkNum); + if (err != ESP_OK) { + if (err == ESP_ERR_NVS_NOT_FOUND) { + break; + } + return err; + } + err = findPage->cmpItem(nsIndex, ItemType::BLOB_DATA, key, static_cast(data) + offset, item.varLength.dataSize, static_cast (chunkStart) + chunkNum); + if (err != ESP_OK) { + return err; + } + assert(static_cast (chunkStart) + chunkNum == item.chunkIndex); + offset += item.varLength.dataSize; + } + if (err == ESP_OK) { + assert(offset == dataSize); + } + return err; +} + esp_err_t Storage::readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize) { if (mState != StorageState::ACTIVE) { @@ -195,12 +535,64 @@ esp_err_t Storage::readItem(uint8_t nsIndex, ItemType datatype, const char* key, Item item; Page* findPage = nullptr; + if (datatype == ItemType::BLOB) { + auto err = readMultiPageBlob(nsIndex, key, data, dataSize); + if (err != ESP_ERR_NVS_NOT_FOUND) { + return err; + } // else check if the blob is stored with earlier version format without index + } + auto err = findItem(nsIndex, datatype, key, findPage, item); if (err != ESP_OK) { return err; } - return findPage->readItem(nsIndex, datatype, key, data, dataSize); + +} + +esp_err_t Storage::eraseMultiPageBlob(uint8_t nsIndex, const char* key, VerOffset chunkStart) +{ + if (mState != StorageState::ACTIVE) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + Item item; + Page* findPage = nullptr; + + auto err = findItem(nsIndex, ItemType::BLOB_IDX, key, findPage, item, Page::CHUNK_ANY, chunkStart); + if (err != ESP_OK) { + return err; + } + /* Erase the index first and make children blobs orphan*/ + err = findPage->eraseItem(nsIndex, ItemType::BLOB_IDX, key, Page::CHUNK_ANY, chunkStart); + if (err != ESP_OK) { + return err; + } + + uint8_t chunkCount = item.blobIndex.chunkCount; + + if (chunkStart == VerOffset::VER_ANY) { + chunkStart = item.blobIndex.chunkStart; + } else { + assert(chunkStart == item.blobIndex.chunkStart); + } + + /* Now erase corresponding chunks*/ + for (uint8_t chunkNum = 0; chunkNum < chunkCount; chunkNum++) { + err = findItem(nsIndex, ItemType::BLOB_DATA, key, findPage, item, static_cast (chunkStart) + chunkNum); + + if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) { + return err; + } else if (err == ESP_ERR_NVS_NOT_FOUND) { + continue; // Keep erasing other chunks + } + err = findPage->eraseItem(nsIndex, ItemType::BLOB_DATA, key, static_cast (chunkStart) + chunkNum); + if (err != ESP_OK) { + return err; + } + + } + + return ESP_OK; } esp_err_t Storage::eraseItem(uint8_t nsIndex, ItemType datatype, const char* key) @@ -209,6 +601,10 @@ esp_err_t Storage::eraseItem(uint8_t nsIndex, ItemType datatype, const char* key return ESP_ERR_NVS_NOT_INITIALIZED; } + if (datatype == ItemType::BLOB) { + return eraseMultiPageBlob(nsIndex, key); + } + Item item; Page* findPage = nullptr; auto err = findItem(nsIndex, datatype, key, findPage, item); @@ -216,6 +612,10 @@ esp_err_t Storage::eraseItem(uint8_t nsIndex, ItemType datatype, const char* key return err; } + if (item.datatype == ItemType::BLOB_DATA || item.datatype == ItemType::BLOB_IDX) { + return eraseMultiPageBlob(nsIndex, key); + } + return findPage->eraseItem(nsIndex, datatype, key); } @@ -250,7 +650,15 @@ esp_err_t Storage::getItemDataSize(uint8_t nsIndex, ItemType datatype, const cha Page* findPage = nullptr; auto err = findItem(nsIndex, datatype, key, findPage, item); if (err != ESP_OK) { - return err; + if (datatype != ItemType::BLOB) { + return err; + } + err = findItem(nsIndex, ItemType::BLOB_IDX, key, findPage, item); + if (err != ESP_OK) { + return err; + } + dataSize = item.blobIndex.dataSize; + return ESP_OK; } dataSize = item.varLength.dataSize; @@ -264,18 +672,18 @@ void Storage::debugDump() } } -#ifndef ESP_PLATFORM +#ifdef DEBUG_STORAGE void Storage::debugCheck() { std::map keys; - + for (auto p = mPageManager.begin(); p != mPageManager.end(); ++p) { size_t itemIndex = 0; size_t usedCount = 0; Item item; while (p->findItem(Page::NS_ANY, ItemType::ANY, nullptr, itemIndex, item) == ESP_OK) { std::stringstream keyrepr; - keyrepr << static_cast(item.nsIndex) << "_" << static_cast(item.datatype) << "_" << item.key; + keyrepr << static_cast(item.nsIndex) << "_" << static_cast(item.datatype) << "_" << item.key <<"_"<(item.chunkIndex); std::string keystr = keyrepr.str(); if (keys.find(keystr) != std::end(keys)) { printf("Duplicate key: %s\n", keystr.c_str()); @@ -289,6 +697,104 @@ void Storage::debugCheck() assert(usedCount == p->getUsedEntryCount()); } } -#endif //ESP_PLATFORM +#endif //DEBUG_STORAGE + +esp_err_t Storage::fillStats(nvs_stats_t& nvsStats) +{ + nvsStats.namespace_count = mNamespaces.size(); + return mPageManager.fillStats(nvsStats); +} + +esp_err_t Storage::calcEntriesInNamespace(uint8_t nsIndex, size_t& usedEntries) +{ + usedEntries = 0; + + if (mState != StorageState::ACTIVE) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) { + size_t itemIndex = 0; + Item item; + while (true) { + auto err = it->findItem(nsIndex, ItemType::ANY, nullptr, itemIndex, item); + if (err == ESP_ERR_NVS_NOT_FOUND) { + break; + } + else if (err != ESP_OK) { + return err; + } + usedEntries += item.span; + itemIndex += item.span; + if (itemIndex >= it->ENTRY_COUNT) break; + } + } + return ESP_OK; +} + +void Storage::fillEntryInfo(Item &item, nvs_entry_info_t &info) +{ + info.type = static_cast(item.datatype); + strncpy(info.key, item.key, sizeof(info.key)); + + for (auto &name : mNamespaces) { + if(item.nsIndex == name.mIndex) { + strncpy(info.namespace_name, name.mName, sizeof(info.namespace_name)); + break; + } + } +} + +bool Storage::findEntry(nvs_opaque_iterator_t* it, const char* namespace_name) +{ + it->entryIndex = 0; + it->nsIndex = Page::NS_ANY; + it->page = mPageManager.begin(); + + if (namespace_name != nullptr) { + if(createOrOpenNamespace(namespace_name, false, it->nsIndex) != ESP_OK) { + return false; + } + } + + return nextEntry(it); +} + +inline bool isIterableItem(Item& item) +{ + return (item.nsIndex != 0 && + item.datatype != ItemType::BLOB && + item.datatype != ItemType::BLOB_IDX); +} + +inline bool isMultipageBlob(Item& item) +{ + return (item.datatype == ItemType::BLOB_DATA && + !(item.chunkIndex == static_cast(VerOffset::VER_0_OFFSET) + || item.chunkIndex == static_cast(VerOffset::VER_1_OFFSET))); +} + +bool Storage::nextEntry(nvs_opaque_iterator_t* it) +{ + Item item; + esp_err_t err; + + for (auto page = it->page; page != mPageManager.end(); ++page) { + do { + err = page->findItem(it->nsIndex, (ItemType)it->type, nullptr, it->entryIndex, item); + it->entryIndex += item.span; + if(err == ESP_OK && isIterableItem(item) && !isMultipageBlob(item)) { + fillEntryInfo(item, it->entry_info); + it->page = page; + return true; + } + } while (err != ESP_ERR_NVS_NOT_FOUND); + + it->entryIndex = 0; + } + + return false; +} + } diff --git a/components/nvs_flash/src/nvs_storage.hpp b/components/nvs_flash/src/nvs_storage.hpp index 3c0e0c85a..fd6eb1cc9 100644 --- a/components/nvs_flash/src/nvs_storage.hpp +++ b/components/nvs_flash/src/nvs_storage.hpp @@ -15,12 +15,12 @@ #define nvs_storage_hpp #include -#include #include #include "nvs.hpp" #include "nvs_types.hpp" #include "nvs_page.hpp" #include "nvs_pagemanager.hpp" +#include "partition.hpp" //extern void dumpBytes(const uint8_t* data, size_t count); @@ -42,10 +42,30 @@ class Storage : public intrusive_list_node typedef intrusive_list TNamespaces; + struct UsedPageNode: public intrusive_list_node { + public: Page* mPage; + }; + + typedef intrusive_list TUsedPageList; + + struct BlobIndexNode: public intrusive_list_node { + public: + char key[Item::MAX_KEY_LENGTH + 1]; + uint8_t nsIndex; + uint8_t chunkCount; + VerOffset chunkStart; + }; + + typedef intrusive_list TBlobIndexList; + public: ~Storage(); - Storage(const char *pName = NVS_DEFAULT_PART_NAME) : mPartitionName(pName) { }; + Storage(Partition *partition) : mPartition(partition) { + if (partition == nullptr) { + abort(); + } + }; esp_err_t init(uint32_t baseSector, uint32_t sectorCount); @@ -77,18 +97,43 @@ class Storage : public intrusive_list_node { return eraseItem(nsIndex, ItemType::ANY, key); } - + esp_err_t eraseNamespace(uint8_t nsIndex); + const Partition *getPart() const + { + return mPartition; + } + const char *getPartName() const { - return mPartitionName; + return mPartition->get_partition_name(); + } + + uint32_t getBaseSector() + { + return mPageManager.getBaseSector(); } + esp_err_t writeMultiPageBlob(uint8_t nsIndex, const char* key, const void* data, size_t dataSize, VerOffset chunkStart); + + esp_err_t readMultiPageBlob(uint8_t nsIndex, const char* key, void* data, size_t dataSize); + + esp_err_t cmpMultiPageBlob(uint8_t nsIndex, const char* key, const void* data, size_t dataSize); + + esp_err_t eraseMultiPageBlob(uint8_t nsIndex, const char* key, VerOffset chunkStart = VerOffset::VER_ANY); + void debugDump(); - + void debugCheck(); + esp_err_t fillStats(nvs_stats_t& nvsStats); + + esp_err_t calcEntriesInNamespace(uint8_t nsIndex, size_t& usedEntries); + + bool findEntry(nvs_opaque_iterator_t*, const char* name); + + bool nextEntry(nvs_opaque_iterator_t* it); protected: @@ -99,10 +144,16 @@ class Storage : public intrusive_list_node void clearNamespaces(); - esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item); + esp_err_t populateBlobIndices(TBlobIndexList&); + + void eraseOrphanDataBlobs(TBlobIndexList&); + + void fillEntryInfo(Item &item, nvs_entry_info_t &info); + + esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item, uint8_t chunkIdx = Page::CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY); protected: - const char *mPartitionName; + Partition *mPartition; size_t mPageCount; PageManager mPageManager; TNamespaces mNamespaces; @@ -112,6 +163,14 @@ class Storage : public intrusive_list_node } // namespace nvs - +struct nvs_opaque_iterator_t +{ + nvs_type_t type; + uint8_t nsIndex; + size_t entryIndex; + nvs::Storage *storage; + intrusive_list::iterator page; + nvs_entry_info_t entry_info; +}; #endif /* nvs_storage_hpp */ diff --git a/components/nvs_flash/src/nvs_test_api.h b/components/nvs_flash/src/nvs_test_api.h index 3cf3e7fa1..8ba2c4faa 100644 --- a/components/nvs_flash/src/nvs_test_api.h +++ b/components/nvs_flash/src/nvs_test_api.h @@ -17,22 +17,38 @@ #ifdef __cplusplus extern "C" { #endif - + #include "nvs_flash.h" /** * @brief Initialize NVS flash storage with custom flash sector layout * * @note This API is intended to be used in unit tests. - * + * * @param partName Partition name of the NVS partition as per partition table * @param baseSector Flash sector (units of 4096 bytes) offset to start NVS - * @param sectorCount Length (in flash sectors) of NVS region. + * @param sectorCount Length (in flash sectors) of NVS region. NVS partition must be at least 3 sectors long. * @return ESP_OK if flash was successfully initialized */ esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount); +#ifdef CONFIG_NVS_ENCRYPTION +/** + * @brief Initialize NVS flash storage with custom flash sector layout + * + * @note This API is intended to be used in unit tests. + * + * @param partName Partition name of the NVS partition as per partition table + * @param baseSector Flash sector (units of 4096 bytes) offset to start NVS + * @param sectorCount Length (in flash sectors) of NVS region. + NVS partition must be at least 3 sectors long. + * @param[in] cfg Security configuration (keys) to be used for NVS encryption/decryption. + * If cfg is null, no encryption/decryption is used. + * @return ESP_OK if flash was successfully initialized + */ +esp_err_t nvs_flash_secure_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount, nvs_sec_cfg_t* cfg); +#endif /** * @brief Dump contents of NVS storage to stdout diff --git a/components/nvs_flash/src/nvs_types.cpp b/components/nvs_flash/src/nvs_types.cpp index 8a1a42fb2..0189dd70b 100644 --- a/components/nvs_flash/src/nvs_types.cpp +++ b/components/nvs_flash/src/nvs_types.cpp @@ -13,7 +13,11 @@ // limitations under the License. #include "nvs_types.hpp" -#include +#if defined(LINUX_TARGET) +#include "crc.h" +#else +#include +#endif namespace nvs { @@ -21,10 +25,10 @@ uint32_t Item::calculateCrc32() const { uint32_t result = 0xffffffff; const uint8_t* p = reinterpret_cast(this); - result = crc32_le(result, p + offsetof(Item, nsIndex), + result = esp_rom_crc32_le(result, p + offsetof(Item, nsIndex), offsetof(Item, crc32) - offsetof(Item, nsIndex)); - result = crc32_le(result, p + offsetof(Item, key), sizeof(key)); - result = crc32_le(result, p + offsetof(Item, data), sizeof(data)); + result = esp_rom_crc32_le(result, p + offsetof(Item, key), sizeof(key)); + result = esp_rom_crc32_le(result, p + offsetof(Item, data), sizeof(data)); return result; } @@ -32,16 +36,17 @@ uint32_t Item::calculateCrc32WithoutValue() const { uint32_t result = 0xffffffff; const uint8_t* p = reinterpret_cast(this); - result = crc32_le(result, p + offsetof(Item, nsIndex), + result = esp_rom_crc32_le(result, p + offsetof(Item, nsIndex), offsetof(Item, datatype) - offsetof(Item, nsIndex)); - result = crc32_le(result, p + offsetof(Item, key), sizeof(key)); + result = esp_rom_crc32_le(result, p + offsetof(Item, key), sizeof(key)); + result = esp_rom_crc32_le(result, p + offsetof(Item, chunkIndex), sizeof(chunkIndex)); return result; } uint32_t Item::calculateCrc32(const uint8_t* data, size_t size) { uint32_t result = 0xffffffff; - result = crc32_le(result, data, size); + result = esp_rom_crc32_le(result, data, size); return result; } diff --git a/components/nvs_flash/src/nvs_types.hpp b/components/nvs_flash/src/nvs_types.hpp index 5306744b5..d05d4d94b 100644 --- a/components/nvs_flash/src/nvs_types.hpp +++ b/components/nvs_flash/src/nvs_types.hpp @@ -15,41 +15,36 @@ #define nvs_types_h #include -#include #include #include #include #include "nvs.h" +#include "nvs_handle.hpp" #include "compressed_enum_table.hpp" +#include "string.h" +using namespace std; namespace nvs { -enum class ItemType : uint8_t { - U8 = 0x01, - I8 = 0x11, - U16 = 0x02, - I16 = 0x12, - U32 = 0x04, - I32 = 0x14, - U64 = 0x08, - I64 = 0x18, - SZ = 0x21, - BLOB = 0x41, - ANY = 0xff +/** + * Used to recognize transient states of a blob. Once a blob is modified, new chunks with the new data are written + * with a new version. The version is saved in the highest bit of Item::chunkIndex as well as in + * Item::blobIndex::chunkStart. + * If a chunk is modified and hence re-written, the version swaps: 0x0 -> 0x80 or 0x80 -> 0x0. + */ +enum class VerOffset: uint8_t { + VER_0_OFFSET = 0x0, + VER_1_OFFSET = 0x80, + VER_ANY = 0xff, }; -template::value, void*>::type = nullptr> -constexpr ItemType itemTypeOf() +inline bool isVariableLengthType(ItemType type) { - return static_cast(((std::is_signed::value)?0x10:0x00) | sizeof(T)); -} - -template -constexpr ItemType itemTypeOf(const T&) -{ - return itemTypeOf(); + return (type == ItemType::BLOB || + type == ItemType::SZ || + type == ItemType::BLOB_DATA); } class Item @@ -60,15 +55,21 @@ class Item uint8_t nsIndex; ItemType datatype; uint8_t span; - uint8_t reserved; + uint8_t chunkIndex; uint32_t crc32; - char key[16]; + char key[NVS_KEY_NAME_MAX_SIZE]; union { struct { uint16_t dataSize; - uint16_t reserved2; + uint16_t reserved; uint32_t dataCrc32; } varLength; + struct { + uint32_t dataSize; + uint8_t chunkCount; // Number of children data blobs. + VerOffset chunkStart; // Offset from which the chunkIndex for children blobs starts + uint16_t reserved; + } blobIndex; uint8_t data[8]; }; }; @@ -77,8 +78,12 @@ class Item static const size_t MAX_KEY_LENGTH = sizeof(key) - 1; - Item(uint8_t nsIndex, ItemType datatype, uint8_t span, const char* key_) - : nsIndex(nsIndex), datatype(datatype), span(span), reserved(0xff) + // 0xff cannot be used as a valid chunkIndex for blob datatype. + static const uint8_t CHUNK_ANY = 0xff; + + + Item(uint8_t nsIndex, ItemType datatype, uint8_t span, const char* key_, uint8_t chunkIdx = CHUNK_ANY) + : nsIndex(nsIndex), datatype(datatype), span(span), chunkIndex(chunkIdx) { std::fill_n(reinterpret_cast(key), sizeof(key) / 4, 0xffffffff); std::fill_n(reinterpret_cast(data), sizeof(data) / 4, 0xffffffff); @@ -100,7 +105,8 @@ class Item void getKey(char* dst, size_t dstSize) { - strncpy(dst, key, (dstSize @@ -113,6 +119,4 @@ class Item } // namespace nvs - - #endif /* nvs_types_h */ diff --git a/components/nvs_flash/src/partition.hpp b/components/nvs_flash/src/partition.hpp new file mode 100644 index 000000000..4cbfb6d9d --- /dev/null +++ b/components/nvs_flash/src/partition.hpp @@ -0,0 +1,59 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PARTITION_HPP_ +#define PARTITION_HPP_ + +#include "esp_err.h" + +namespace nvs { + +/** + * @brief Abstract interface for partition related operations, currently in NVS. + * + * It resembles the main operations according to esp_partition.h. + */ +class Partition { +public: + virtual ~Partition() { } + + /** + * Return the partition name as in the partition table. + */ + virtual const char *get_partition_name() = 0; + + virtual esp_err_t read_raw(size_t src_offset, void* dst, size_t size) = 0; + + virtual esp_err_t read(size_t src_offset, void* dst, size_t size) = 0; + + virtual esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) = 0; + + virtual esp_err_t write(size_t dst_offset, const void* src, size_t size) = 0; + + virtual esp_err_t erase_range(size_t dst_offset, size_t size) = 0; + + /** + * Return the address of the beginning of the partition. + */ + virtual uint32_t get_address() = 0; + + /** + * Return the partition size in bytes. + */ + virtual uint32_t get_size() = 0; +}; + +} // nvs + +#endif // PARTITION_HPP_ diff --git a/components/nvs_flash/test/CMakeLists.txt b/components/nvs_flash/test/CMakeLists.txt new file mode 100644 index 000000000..f69580398 --- /dev/null +++ b/components/nvs_flash/test/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRC_DIRS "." + PRIV_INCLUDE_DIRS "." + PRIV_REQUIRES cmock test_utils nvs_flash bootloader_support + EMBED_TXTFILES encryption_keys.bin partition_encrypted.bin sample.bin) diff --git a/components/nvs_flash/test/component.mk b/components/nvs_flash/test/component.mk index 5dd172bdb..a0ea7a406 100644 --- a/components/nvs_flash/test/component.mk +++ b/components/nvs_flash/test/component.mk @@ -3,3 +3,4 @@ # COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive +COMPONENT_EMBED_TXTFILES += encryption_keys.bin partition_encrypted.bin sample.bin diff --git a/components/nvs_flash/test/encryption_keys.bin b/components/nvs_flash/test/encryption_keys.bin new file mode 100644 index 000000000..9ef4439d8 --- /dev/null +++ b/components/nvs_flash/test/encryption_keys.bin @@ -0,0 +1 @@ +"""""""""""""""""""""""""""""""",ïÏ<ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ \ No newline at end of file diff --git a/components/nvs_flash/test/partition_encrypted.bin b/components/nvs_flash/test/partition_encrypted.bin new file mode 100644 index 0000000000000000000000000000000000000000..93c900ff4a7e8c5a6cb9f21e28cd1a3cb77110da GIT binary patch literal 8192 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 +#include "esp_system.h" + +#ifdef CONFIG_NVS_ENCRYPTION +#include "mbedtls/aes.h" +#endif static const char* TAG = "test_nvs"; +TEST_CASE("Partition name no longer than 16 characters", "[nvs]") +{ + const char *TOO_LONG_NAME = "0123456789abcdefg"; + + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, nvs_flash_init_partition(TOO_LONG_NAME)); + + nvs_flash_deinit_partition(TOO_LONG_NAME); // just in case +} + +TEST_CASE("flash erase deinitializes initialized partition", "[nvs]") +{ + nvs_handle_t handle; + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + nvs_flash_erase(); + err = nvs_flash_init(); + } + TEST_ESP_OK( err ); + + TEST_ESP_OK(nvs_flash_init()); + TEST_ESP_OK(nvs_open("uninit_ns", NVS_READWRITE, &handle)); + nvs_close(handle); + TEST_ESP_OK(nvs_flash_erase()); + + // exptected: no partition is initialized since nvs_flash_erase() deinitialized the partition again + TEST_ESP_ERR(ESP_ERR_NVS_NOT_INITIALIZED, nvs_open("uninit_ns", NVS_READWRITE, &handle)); + + // just to be sure it's deinitialized in case of error and not affecting other tests + nvs_flash_deinit(); +} + +// test could have different output on host tests +TEST_CASE("nvs deinit with open handle", "[nvs]") +{ + nvs_handle_t handle_1; + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_LOGW(TAG, "nvs_flash_init failed (0x%x), erasing partition and retrying", err); + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); + + TEST_ESP_OK(nvs_open("deinit_ns", NVS_READWRITE, &handle_1)); + nvs_flash_deinit(); +} + TEST_CASE("various nvs tests", "[nvs]") { - nvs_handle handle_1; + nvs_handle_t handle_1; esp_err_t err = nvs_flash_init(); - if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_LOGW(TAG, "nvs_flash_init failed (0x%x), erasing partition and retrying", err); - const esp_partition_t* nvs_partition = esp_partition_find_first( - ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); - assert(nvs_partition && "partition table must have an NVS partition"); - ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + ESP_ERROR_CHECK(nvs_flash_erase()); err = nvs_flash_init(); } ESP_ERROR_CHECK( err ); - TEST_ESP_ERR(nvs_open("test_namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND); + TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, nvs_open("test_namespace1", NVS_READONLY, &handle_1)); - TEST_ESP_ERR(nvs_set_i32(handle_1, "foo", 0x12345678), ESP_ERR_NVS_INVALID_HANDLE); + TEST_ESP_ERR(ESP_ERR_NVS_INVALID_HANDLE, nvs_set_i32(handle_1, "foo", 0x12345678)); nvs_close(handle_1); TEST_ESP_OK(nvs_open("test_namespace2", NVS_READWRITE, &handle_1)); @@ -36,7 +86,7 @@ TEST_CASE("various nvs tests", "[nvs]") TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678)); TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789)); - nvs_handle handle_2; + nvs_handle_t handle_2; TEST_ESP_OK(nvs_open("test_namespace3", NVS_READWRITE, &handle_2)); TEST_ESP_OK(nvs_erase_all(handle_2)); TEST_ESP_OK(nvs_set_i32(handle_2, "foo", 0x3456789a)); @@ -65,3 +115,430 @@ TEST_CASE("various nvs tests", "[nvs]") nvs_close(handle_2); } + +TEST_CASE("calculate used and free space", "[nvs]") +{ + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, nvs_get_stats(NULL, NULL)); + nvs_stats_t stat1; + nvs_stats_t stat2; + TEST_ESP_ERR(ESP_ERR_NVS_NOT_INITIALIZED, nvs_get_stats(NULL, &stat1)); + TEST_ASSERT_TRUE(stat1.free_entries == 0); + TEST_ASSERT_TRUE(stat1.namespace_count == 0); + TEST_ASSERT_TRUE(stat1.total_entries == 0); + TEST_ASSERT_TRUE(stat1.used_entries == 0); + + nvs_handle_t handle = 0; + size_t h_count_entries; + TEST_ESP_ERR(ESP_ERR_NVS_INVALID_HANDLE, nvs_get_used_entry_count(handle, &h_count_entries)); + TEST_ASSERT_TRUE(h_count_entries == 0); + + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_LOGW(TAG, "nvs_flash_init failed (0x%x), erasing partition and retrying", err); + const esp_partition_t* nvs_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + assert(nvs_partition && "partition table must have an NVS partition"); + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); + + // erase if have any namespace + TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); + if(stat1.namespace_count != 0) { + TEST_ESP_OK(nvs_flash_deinit()); + TEST_ESP_OK(nvs_flash_erase()); + TEST_ESP_OK(nvs_flash_init()); + } + + // after erase. empty partition + TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); + TEST_ASSERT_TRUE(stat1.free_entries != 0); + TEST_ASSERT_TRUE(stat1.namespace_count == 0); + TEST_ASSERT_TRUE(stat1.total_entries != 0); + TEST_ASSERT_TRUE(stat1.used_entries == 0); + + // create namespace test_k1 + nvs_handle_t handle_1; + TEST_ESP_OK(nvs_open("test_k1", NVS_READWRITE, &handle_1)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat2)); + TEST_ASSERT_TRUE(stat2.free_entries + 1 == stat1.free_entries); + TEST_ASSERT_TRUE(stat2.namespace_count == 1); + TEST_ASSERT_TRUE(stat2.total_entries == stat1.total_entries); + TEST_ASSERT_TRUE(stat2.used_entries == 1); + + // create pair key-value com + TEST_ESP_OK(nvs_set_i32(handle_1, "com", 0x12345678)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); + TEST_ASSERT_TRUE(stat1.free_entries + 1 == stat2.free_entries); + TEST_ASSERT_TRUE(stat1.namespace_count == 1); + TEST_ASSERT_TRUE(stat1.total_entries == stat2.total_entries); + TEST_ASSERT_TRUE(stat1.used_entries == 2); + + // change value in com + TEST_ESP_OK(nvs_set_i32(handle_1, "com", 0x01234567)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat2)); + TEST_ASSERT_TRUE(stat2.free_entries == stat1.free_entries); + TEST_ASSERT_TRUE(stat2.namespace_count == 1); + TEST_ASSERT_TRUE(stat2.total_entries != 0); + TEST_ASSERT_TRUE(stat2.used_entries == 2); + + // create pair key-value ru + TEST_ESP_OK(nvs_set_i32(handle_1, "ru", 0x00FF00FF)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); + TEST_ASSERT_TRUE(stat1.free_entries + 1 == stat2.free_entries); + TEST_ASSERT_TRUE(stat1.namespace_count == 1); + TEST_ASSERT_TRUE(stat1.total_entries != 0); + TEST_ASSERT_TRUE(stat1.used_entries == 3); + + // amount valid pair in namespace 1 + size_t h1_count_entries; + TEST_ESP_OK(nvs_get_used_entry_count(handle_1, &h1_count_entries)); + TEST_ASSERT_TRUE(h1_count_entries == 2); + + nvs_handle_t handle_2; + // create namespace test_k2 + TEST_ESP_OK(nvs_open("test_k2", NVS_READWRITE, &handle_2)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat2)); + TEST_ASSERT_TRUE(stat2.free_entries + 1 == stat1.free_entries); + TEST_ASSERT_TRUE(stat2.namespace_count == 2); + TEST_ASSERT_TRUE(stat2.total_entries == stat1.total_entries); + TEST_ASSERT_TRUE(stat2.used_entries == 4); + + // create pair key-value + TEST_ESP_OK(nvs_set_i32(handle_2, "su1", 0x00000001)); + TEST_ESP_OK(nvs_set_i32(handle_2, "su2", 0x00000002)); + TEST_ESP_OK(nvs_set_i32(handle_2, "sus", 0x00000003)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); + TEST_ASSERT_TRUE(stat1.free_entries + 3 == stat2.free_entries); + TEST_ASSERT_TRUE(stat1.namespace_count == 2); + TEST_ASSERT_TRUE(stat1.total_entries == stat2.total_entries); + TEST_ASSERT_TRUE(stat1.used_entries == 7); + + TEST_ASSERT_TRUE(stat1.total_entries == (stat1.used_entries + stat1.free_entries)); + + // amount valid pair in namespace 2 + size_t h2_count_entries; + TEST_ESP_OK(nvs_get_used_entry_count(handle_2, &h2_count_entries)); + TEST_ASSERT_TRUE(h2_count_entries == 3); + + TEST_ASSERT_TRUE(stat1.used_entries == (h1_count_entries + h2_count_entries + stat1.namespace_count)); + + nvs_close(handle_1); + nvs_close(handle_2); + + size_t temp = h2_count_entries; + TEST_ESP_ERR(ESP_ERR_NVS_INVALID_HANDLE, nvs_get_used_entry_count(handle_1, &h2_count_entries)); + TEST_ASSERT_TRUE(h2_count_entries == 0); + h2_count_entries = temp; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, nvs_get_used_entry_count(handle_1, NULL)); + + nvs_handle_t handle_3; + // create namespace test_k3 + TEST_ESP_OK(nvs_open("test_k3", NVS_READWRITE, &handle_3)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat2)); + TEST_ASSERT_TRUE(stat2.free_entries + 1 == stat1.free_entries); + TEST_ASSERT_TRUE(stat2.namespace_count == 3); + TEST_ASSERT_TRUE(stat2.total_entries == stat1.total_entries); + TEST_ASSERT_TRUE(stat2.used_entries == 8); + + // create pair blobs + uint32_t blob[12]; + TEST_ESP_OK(nvs_set_blob(handle_3, "bl1", &blob, sizeof(blob))); + TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); + TEST_ASSERT_TRUE(stat1.free_entries + 4 == stat2.free_entries); + TEST_ASSERT_TRUE(stat1.namespace_count == 3); + TEST_ASSERT_TRUE(stat1.total_entries == stat2.total_entries); + TEST_ASSERT_TRUE(stat1.used_entries == 12); + + // amount valid pair in namespace 2 + size_t h3_count_entries; + TEST_ESP_OK(nvs_get_used_entry_count(handle_3, &h3_count_entries)); + TEST_ASSERT_TRUE(h3_count_entries == 4); + + TEST_ASSERT_TRUE(stat1.used_entries == (h1_count_entries + h2_count_entries + h3_count_entries + stat1.namespace_count)); + + nvs_close(handle_3); + + TEST_ESP_OK(nvs_flash_deinit()); + TEST_ESP_OK(nvs_flash_erase()); +} + +TEST_CASE("check for memory leaks in nvs_set_blob", "[nvs]") +{ + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + TEST_ESP_OK( err ); + + for (int i = 0; i < 500; ++i) { + nvs_handle_t my_handle; + uint8_t key[20] = {0}; + + TEST_ESP_OK( nvs_open("leak_check_ns", NVS_READWRITE, &my_handle) ); + TEST_ESP_OK( nvs_set_blob(my_handle, "key", key, sizeof(key)) ); + TEST_ESP_OK( nvs_commit(my_handle) ); + nvs_close(my_handle); + printf("%d\n", esp_get_free_heap_size()); + } + + nvs_flash_deinit(); + printf("%d\n", esp_get_free_heap_size()); + /* heap leaks will be checked in unity_platform.c */ +} + +#ifdef CONFIG_NVS_ENCRYPTION +TEST_CASE("check underlying xts code for 32-byte size sector encryption", "[nvs]") +{ + uint8_t eky_hex[2 * NVS_KEY_SIZE] = { 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + /* Tweak key below*/ + 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, + 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, + 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, + 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22 }; + + uint8_t ba_hex[16] = { 0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + + uint8_t ptxt_hex[32] = { 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44 }; + + + uint8_t ctxt_hex[32] = { 0xe6,0x22,0x33,0x4f,0x18,0x4b,0xbc,0xe1, + 0x29,0xa2,0x5b,0x2a,0xc7,0x6b,0x3d,0x92, + 0xab,0xf9,0x8e,0x22,0xdf,0x5b,0xdd,0x15, + 0xaf,0x47,0x1f,0x3d,0xb8,0x94,0x6a,0x85 }; + + mbedtls_aes_xts_context ectx[1]; + mbedtls_aes_xts_context dctx[1]; + + mbedtls_aes_xts_init(ectx); + mbedtls_aes_xts_init(dctx); + + TEST_ASSERT_TRUE(!mbedtls_aes_xts_setkey_enc(ectx, eky_hex, 2 * NVS_KEY_SIZE * 8)); + TEST_ASSERT_TRUE(!mbedtls_aes_xts_setkey_enc(dctx, eky_hex, 2 * NVS_KEY_SIZE * 8)); + + TEST_ASSERT_TRUE(!mbedtls_aes_crypt_xts(ectx, MBEDTLS_AES_ENCRYPT, 32, ba_hex, ptxt_hex, ptxt_hex)); + + TEST_ASSERT_TRUE(!memcmp(ptxt_hex, ctxt_hex, 32)); +} + +TEST_CASE("Check nvs key partition APIs (read and generate keys)", "[nvs]") +{ + nvs_sec_cfg_t cfg, cfg2; + + const esp_partition_t* key_part = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL); + + if (!esp_flash_encryption_enabled()) { + TEST_IGNORE_MESSAGE("flash encryption disabled, skipping nvs_key partition related tests"); + } + + TEST_ESP_OK(esp_partition_erase_range(key_part, 0, key_part->size)); + TEST_ESP_ERR(ESP_ERR_NVS_KEYS_NOT_INITIALIZED, nvs_flash_read_security_cfg(key_part, &cfg)); + + TEST_ESP_OK(nvs_flash_generate_keys(key_part, &cfg)); + + TEST_ESP_OK(nvs_flash_read_security_cfg(key_part, &cfg2)); + + TEST_ASSERT_TRUE(!memcmp(&cfg, &cfg2, sizeof(nvs_sec_cfg_t))); +} + + +TEST_CASE("test nvs apis with encryption enabled", "[nvs]") +{ + if (!esp_flash_encryption_enabled()) { + TEST_IGNORE_MESSAGE("flash encryption disabled, skipping nvs_api tests with encryption enabled"); + } + const esp_partition_t* key_part = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL); + + assert(key_part && "partition table must have an NVS Key partition"); + + const esp_partition_t* nvs_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + assert(nvs_partition && "partition table must have an NVS partition"); + + ESP_ERROR_CHECK( esp_partition_erase_range(key_part, 0, key_part->size) ); + + bool done = false; + + do { + ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + + nvs_sec_cfg_t cfg; + esp_err_t err = nvs_flash_read_security_cfg(key_part, &cfg); + + if(err == ESP_ERR_NVS_KEYS_NOT_INITIALIZED) { + uint8_t value[4096] = {[0 ... 4095] = 0xff}; + TEST_ESP_OK(esp_partition_write(key_part, 0, value, sizeof(value))); + + TEST_ESP_ERR(ESP_ERR_NVS_KEYS_NOT_INITIALIZED, nvs_flash_read_security_cfg(key_part, &cfg)); + + TEST_ESP_OK(nvs_flash_generate_keys(key_part, &cfg)); + } else { + /* Second time key_partition exists already*/ + ESP_ERROR_CHECK(err); + done = true; + } + TEST_ESP_OK(nvs_flash_secure_init(&cfg)); + + nvs_handle_t handle_1; + + TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, nvs_open("namespace1", NVS_READONLY, &handle_1)); + + + TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1)); + + TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678)); + TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789)); + + nvs_handle_t handle_2; + TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2)); + TEST_ESP_OK(nvs_set_i32(handle_2, "foo", 0x3456789a)); + const char* str = "value 0123456789abcdef0123456789abcdef"; + TEST_ESP_OK(nvs_set_str(handle_2, "key", str)); + + int32_t v1; + TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1)); + TEST_ASSERT_TRUE(0x23456789 == v1); + + int32_t v2; + TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2)); + TEST_ASSERT_TRUE(0x3456789a == v2); + + char buf[strlen(str) + 1]; + size_t buf_len = sizeof(buf); + + size_t buf_len_needed; + TEST_ESP_OK(nvs_get_str(handle_2, "key", NULL, &buf_len_needed)); + TEST_ASSERT_TRUE(buf_len_needed == buf_len); + + size_t buf_len_short = buf_len - 1; + TEST_ESP_ERR(ESP_ERR_NVS_INVALID_LENGTH, nvs_get_str(handle_2, "key", buf, &buf_len_short)); + TEST_ASSERT_TRUE(buf_len_short == buf_len); + + size_t buf_len_long = buf_len + 1; + TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len_long)); + TEST_ASSERT_TRUE(buf_len_long == buf_len); + + TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len)); + + TEST_ASSERT_TRUE(0 == strcmp(buf, str)); + + nvs_close(handle_1); + nvs_close(handle_2); + + TEST_ESP_OK(nvs_flash_deinit()); + } while(!done); +} + +TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled", "[nvs_part_gen]") +{ + + if (!esp_flash_encryption_enabled()) { + TEST_IGNORE_MESSAGE("flash encryption disabled, skipping nvs_api tests with encryption enabled"); + } + + nvs_handle_t handle; + nvs_sec_cfg_t xts_cfg; + + extern const char nvs_key_start[] asm("_binary_encryption_keys_bin_start"); + extern const char nvs_key_end[] asm("_binary_encryption_keys_bin_end"); + + extern const char nvs_data_start[] asm("_binary_partition_encrypted_bin_start"); + + extern const char sample_bin_start[] asm("_binary_sample_bin_start"); + + const esp_partition_t* key_part = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL); + + const esp_partition_t* nvs_part = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + + assert(key_part && "partition table must have a KEY partition"); + TEST_ASSERT_TRUE((nvs_key_end - nvs_key_start - 1) == SPI_FLASH_SEC_SIZE); + + assert(nvs_part && "partition table must have an NVS partition"); + printf("\n nvs_part size:%d\n", nvs_part->size); + + ESP_ERROR_CHECK(esp_partition_erase_range(key_part, 0, key_part->size)); + ESP_ERROR_CHECK( esp_partition_erase_range(nvs_part, 0, nvs_part->size) ); + + for (int i = 0; i < key_part->size; i+= SPI_FLASH_SEC_SIZE) { + ESP_ERROR_CHECK( esp_partition_write(key_part, i, nvs_key_start + i, SPI_FLASH_SEC_SIZE) ); + } + + for (int i = 0; i < nvs_part->size; i+= SPI_FLASH_SEC_SIZE) { + ESP_ERROR_CHECK( esp_partition_write(nvs_part, i, nvs_data_start + i, SPI_FLASH_SEC_SIZE) ); + } + + esp_err_t err = nvs_flash_read_security_cfg(key_part, &xts_cfg); + ESP_ERROR_CHECK(err); + + TEST_ESP_OK(nvs_flash_secure_init(&xts_cfg)); + + TEST_ESP_OK(nvs_open("dummyNamespace", NVS_READONLY, &handle)); + uint8_t u8v; + TEST_ESP_OK( nvs_get_u8(handle, "dummyU8Key", &u8v)); + TEST_ASSERT_TRUE(u8v == 127); + int8_t i8v; + TEST_ESP_OK( nvs_get_i8(handle, "dummyI8Key", &i8v)); + TEST_ASSERT_TRUE(i8v == -128); + uint16_t u16v; + TEST_ESP_OK( nvs_get_u16(handle, "dummyU16Key", &u16v)); + TEST_ASSERT_TRUE(u16v == 32768); + uint32_t u32v; + TEST_ESP_OK( nvs_get_u32(handle, "dummyU32Key", &u32v)); + TEST_ASSERT_TRUE(u32v == 4294967295); + int32_t i32v; + TEST_ESP_OK( nvs_get_i32(handle, "dummyI32Key", &i32v)); + TEST_ASSERT_TRUE(i32v == -2147483648); + + char buf[64] = {0}; + size_t buflen = 64; + TEST_ESP_OK( nvs_get_str(handle, "dummyStringKey", buf, &buflen)); + TEST_ASSERT_TRUE(strncmp(buf, "0A:0B:0C:0D:0E:0F", buflen) == 0); + + uint8_t hexdata[] = {0x01, 0x02, 0x03, 0xab, 0xcd, 0xef}; + buflen = 64; + TEST_ESP_OK( nvs_get_blob(handle, "dummyHex2BinKey", buf, &buflen)); + TEST_ASSERT_TRUE(memcmp(buf, hexdata, buflen) == 0); + + uint8_t base64data[] = {'1', '2', '3', 'a', 'b', 'c'}; + buflen = 64; + TEST_ESP_OK( nvs_get_blob(handle, "dummyBase64Key", buf, &buflen)); + TEST_ASSERT_TRUE(memcmp(buf, base64data, buflen) == 0); + + uint8_t hexfiledata[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}; + buflen = 64; + TEST_ESP_OK( nvs_get_blob(handle, "hexFileKey", buf, &buflen)); + TEST_ASSERT_TRUE(memcmp(buf, hexfiledata, buflen) == 0); + + uint8_t base64filedata[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xab, 0xcd, 0xef}; + buflen = 64; + TEST_ESP_OK( nvs_get_blob(handle, "base64FileKey", buf, &buflen)); + TEST_ASSERT_TRUE(memcmp(buf, base64filedata, buflen) == 0); + + uint8_t strfiledata[64] = "abcdefghijklmnopqrstuvwxyz\0"; + buflen = 64; + TEST_ESP_OK( nvs_get_str(handle, "stringFileKey", buf, &buflen)); + TEST_ASSERT_TRUE(memcmp(buf, strfiledata, buflen) == 0); + + char bin_data[5120]; + size_t bin_len = sizeof(bin_data); + TEST_ESP_OK( nvs_get_blob(handle, "binFileKey", bin_data, &bin_len)); + TEST_ASSERT_TRUE(memcmp(bin_data, sample_bin_start, bin_len) == 0); + + nvs_close(handle); + TEST_ESP_OK(nvs_flash_deinit()); + +} +#endif diff --git a/components/nvs_flash/test_nvs_host/Makefile b/components/nvs_flash/test_nvs_host/Makefile index f1f5b52f2..5031de6a8 100644 --- a/components/nvs_flash/test_nvs_host/Makefile +++ b/components/nvs_flash/test_nvs_host/Makefile @@ -3,6 +3,7 @@ all: $(TEST_PROGRAM) SOURCE_FILES = \ esp_error_check_stub.cpp \ + ../mock/int/crc.cpp \ $(addprefix ../src/, \ nvs_types.cpp \ nvs_api.cpp \ @@ -10,37 +11,61 @@ SOURCE_FILES = \ nvs_pagemanager.cpp \ nvs_storage.cpp \ nvs_item_hash_list.cpp \ + nvs_handle_simple.cpp \ + nvs_handle_locked.cpp \ + nvs_partition_manager.cpp \ + nvs_partition.cpp \ + nvs_encrypted_partition.cpp \ + nvs_cxx_api.cpp \ ) \ spi_flash_emulation.cpp \ test_compressed_enum_table.cpp \ test_spi_flash_emulation.cpp \ test_intrusive_list.cpp \ test_nvs.cpp \ - crc.cpp \ + test_partition_manager.cpp \ + test_nvs_handle.cpp \ + test_nvs_storage.cpp \ + test_nvs_partition.cpp \ + test_nvs_cxx_api.cpp \ + test_nvs_initialization.cpp \ main.cpp -CPPFLAGS += -I../include -I../src -I./ -I../../esp32/include -I ../../spi_flash/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -CFLAGS += -fprofile-arcs -ftest-coverage -CXXFLAGS += -std=c++11 -Wall -Werror +ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1) +COMPILER := clang +else +COMPILER := gcc +endif + +CPPFLAGS += -I../include -I../src -I../mock/int -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../hal/include -I ../../xtensa/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -g2 -ggdb +CFLAGS += -fprofile-arcs -ftest-coverage -DLINUX_TARGET +CXXFLAGS += -std=c++11 -Wall -Werror -DLINUX_TARGET LDFLAGS += -lstdc++ -Wall -fprofile-arcs -ftest-coverage +ifeq ($(COMPILER),clang) +CFLAGS += -fsanitize=address +CXXFLAGS += -fsanitize=address +LDFLAGS += -fsanitize=address +endif + OBJ_FILES = $(SOURCE_FILES:.cpp=.o) COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(OBJ_FILES): %.o: %.cpp -$(TEST_PROGRAM): $(OBJ_FILES) - g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES) +$(TEST_PROGRAM): clean-coverage $(OBJ_FILES) + $(MAKE) -C ../../mbedtls/mbedtls/ lib + g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES) ../../mbedtls/mbedtls/library/libmbedcrypto.a $(OUTPUT_DIR): mkdir -p $(OUTPUT_DIR) test: $(TEST_PROGRAM) - ./$(TEST_PROGRAM) + ./$(TEST_PROGRAM) -d yes exclude:[long] long-test: $(TEST_PROGRAM) - ./$(TEST_PROGRAM) [list],[enumtable],[spi_flash_emu],[nvs],[long] + ./$(TEST_PROGRAM) -d yes $(COVERAGE_FILES): $(TEST_PROGRAM) long-test @@ -52,10 +77,26 @@ coverage_report: coverage.info genhtml coverage.info --output-directory coverage_report @echo "Coverage report is in coverage_report/index.html" -clean: - rm -f $(OBJ_FILES) $(TEST_PROGRAM) +clean-coverage: rm -f $(COVERAGE_FILES) *.gcov rm -rf coverage_report/ rm -f coverage.info -.PHONY: clean all test +clean: clean-coverage + $(MAKE) -C ../../mbedtls/mbedtls/ clean + rm -f $(OBJ_FILES) $(TEST_PROGRAM) + rm -f ../nvs_partition_generator/partition_single_page.bin + rm -f ../nvs_partition_generator/partition_multipage_blob.bin + rm -f ../nvs_partition_generator/partition_encrypted.bin + rm -f ../nvs_partition_generator/partition_encrypted_using_keygen.bin + rm -f ../nvs_partition_generator/partition_encrypted_using_keyfile.bin + rm -f ../nvs_partition_generator/partition_decrypted.bin + rm -f ../nvs_partition_generator/partition_encoded.bin + rm -f ../nvs_partition_generator/Test-1-partition-encrypted.bin + rm -f ../nvs_partition_generator/Test-1-partition.bin + rm -f ../../../tools/mass_mfg/samples/sample_values_multipage_blob_created.csv + rm -f ../../../tools/mass_mfg/samples/sample_values_singlepage_blob_created.csv + + + +.PHONY: clean clean-coverage all test long-test diff --git a/components/nvs_flash/test_nvs_host/README.md b/components/nvs_flash/test_nvs_host/README.md new file mode 100644 index 000000000..bad5b08cd --- /dev/null +++ b/components/nvs_flash/test_nvs_host/README.md @@ -0,0 +1,22 @@ +# Build + +```bash +make -j 6 +``` + +# Run +* Run particular test case: +```bash +./test_nvs "" + +``` +* Run all quick tests: +```bash +./test_nvs -d yes exclude:[long] +``` + +* Run all tests (takes several hours) +```bash +./test_nvs -d yes +``` + diff --git a/components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp b/components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp index 9cff4af31..34d8704e7 100644 --- a/components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp +++ b/components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp @@ -1,9 +1,14 @@ #include "catch.hpp" #include "esp_err.h" +#include "sdkconfig.h" void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) { - printf("ESP_ERROR_CHECK failed: esp_err_t 0x%x at %p\n", rc, __builtin_return_address(0)); + printf("ESP_ERROR_CHECK failed: esp_err_t 0x%x", rc); +#ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP + printf(" (%s)", esp_err_to_name(rc)); +#endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP + printf(" at %p\n", __builtin_return_address(0)); printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression); abort(); } diff --git a/components/nvs_flash/test_nvs_host/sdkconfig.h b/components/nvs_flash/test_nvs_host/sdkconfig.h index e69de29bb..a38e0a10d 100644 --- a/components/nvs_flash/test_nvs_host/sdkconfig.h +++ b/components/nvs_flash/test_nvs_host/sdkconfig.h @@ -0,0 +1,3 @@ +#define CONFIG_NVS_ENCRYPTION 1 +//currently use the legacy implementation, since the stubs for new HAL are not done yet +#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL 1 diff --git a/components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp b/components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp index 914efc145..802256c1a 100644 --- a/components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp +++ b/components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#include "esp_spi_flash.h" +#include "esp_partition.h" #include "spi_flash_emulation.h" @@ -22,39 +22,82 @@ void spi_flash_emulator_set(SpiFlashEmulator* e) s_emulator = e; } -esp_err_t spi_flash_erase_sector(size_t sec) +esp_err_t esp_partition_erase_range(const esp_partition_t* partition, + size_t offset, size_t size) { if (!s_emulator) { return ESP_ERR_FLASH_OP_TIMEOUT; } - if (!s_emulator->erase(sec)) { + if (size % SPI_FLASH_SEC_SIZE != 0) { + return ESP_ERR_INVALID_SIZE; + } + + if (offset % SPI_FLASH_SEC_SIZE != 0) { + return ESP_ERR_INVALID_ARG; + } + + size_t start_sector = offset / SPI_FLASH_SEC_SIZE; + size_t num_sectors = size / SPI_FLASH_SEC_SIZE; + for (size_t sector = start_sector; sector < (start_sector + num_sectors); sector++) { + if (!s_emulator->erase(sector)) { + return ESP_ERR_FLASH_OP_FAIL; + } + } + + return ESP_OK; +} + +esp_err_t esp_partition_read(const esp_partition_t* partition, + size_t src_offset, void* dst, size_t size) +{ + if (!s_emulator) { + return ESP_ERR_FLASH_OP_TIMEOUT; + } + + if (!s_emulator->read(reinterpret_cast(dst), src_offset, size)) { return ESP_ERR_FLASH_OP_FAIL; } return ESP_OK; } -esp_err_t spi_flash_write(size_t des_addr, const void *src_addr, size_t size) +esp_err_t esp_partition_read_raw(const esp_partition_t* partition, + size_t src_offset, void* dst, size_t size) { if (!s_emulator) { return ESP_ERR_FLASH_OP_TIMEOUT; } - if (!s_emulator->write(des_addr, reinterpret_cast(src_addr), size)) { + if (!s_emulator->read(reinterpret_cast(dst), src_offset, size)) { return ESP_ERR_FLASH_OP_FAIL; } return ESP_OK; } -esp_err_t spi_flash_read(size_t src_addr, void *des_addr, size_t size) +esp_err_t esp_partition_write(const esp_partition_t* partition, + size_t dst_offset, const void* src, size_t size) { if (!s_emulator) { return ESP_ERR_FLASH_OP_TIMEOUT; } - if (!s_emulator->read(reinterpret_cast(des_addr), src_addr, size)) { + if (!s_emulator->write(dst_offset, reinterpret_cast(src), size)) { + return ESP_ERR_FLASH_OP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_partition_write_raw(const esp_partition_t* partition, + size_t dst_offset, const void* src, size_t size) +{ + if (!s_emulator) { + return ESP_ERR_FLASH_OP_TIMEOUT; + } + + if (!s_emulator->write(dst_offset, reinterpret_cast(src), size)) { return ESP_ERR_FLASH_OP_FAIL; } @@ -71,10 +114,11 @@ static size_t blockEraseTime = 37142; static size_t timeInterp(uint32_t bytes, size_t* lut) { + const int lut_size = sizeof(readTimes)/sizeof(readTimes[0]); int lz = __builtin_clz(bytes / 4); int log_size = 32 - lz; size_t x2 = 1 << (log_size + 2); - size_t y2 = lut[log_size]; + size_t y2 = lut[std::min(log_size, lut_size - 1)]; size_t x1 = 1 << (log_size + 1); size_t y1 = lut[log_size - 1]; return (bytes - x1) * (y2 - y1) / (x2 - x1) + y1; @@ -94,4 +138,3 @@ size_t SpiFlashEmulator::getEraseOpTime() { return blockEraseTime; } - diff --git a/components/nvs_flash/test_nvs_host/spi_flash_emulation.h b/components/nvs_flash/test_nvs_host/spi_flash_emulation.h index d8099322d..f2aef6a01 100644 --- a/components/nvs_flash/test_nvs_host/spi_flash_emulation.h +++ b/components/nvs_flash/test_nvs_host/spi_flash_emulation.h @@ -36,6 +36,16 @@ class SpiFlashEmulator SpiFlashEmulator(size_t sectorCount) : mUpperSectorBound(sectorCount) { mData.resize(sectorCount * SPI_FLASH_SEC_SIZE / 4, 0xffffffff); + mEraseCnt.resize(sectorCount); + spi_flash_emulator_set(this); + } + + SpiFlashEmulator(const char *filename) + { + load(filename); + // Atleast one page should be free, hence we create mData of size of 2 sectors. + mData.resize(mData.size() + SPI_FLASH_SEC_SIZE / 4, 0xffffffff); + mUpperSectorBound = mData.size() * 4 / SPI_FLASH_SEC_SIZE; spi_flash_emulator_set(this); } @@ -67,13 +77,13 @@ class SpiFlashEmulator WARN("invalid flash operation detected: erase sector=" << sectorNumber); return false; } - + if (dstAddr % 4 != 0 || size % 4 != 0 || dstAddr + size > mData.size() * 4) { return false; } - + for (size_t i = 0; i < size / 4; ++i) { if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) { return false; @@ -102,12 +112,12 @@ class SpiFlashEmulator if (offset > mData.size()) { return false; } - + if (sectorNumber < mLowerSectorBound || sectorNumber >= mUpperSectorBound) { WARN("invalid flash operation detected: erase sector=" << sectorNumber); return false; } - + if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) { return false; } @@ -115,10 +125,11 @@ class SpiFlashEmulator std::fill_n(begin(mData) + offset, SPI_FLASH_SEC_SIZE / 4, 0xffffffff); ++mEraseOps; + mEraseCnt[sectorNumber]++; mTotalTime += getEraseOpTime(); return true; } - + void randomize(uint32_t seed) { std::random_device rd; @@ -141,7 +152,7 @@ class SpiFlashEmulator { return reinterpret_cast(mData.data()); } - + void load(const char* filename) { FILE* f = fopen(filename, "rb"); @@ -154,7 +165,7 @@ class SpiFlashEmulator assert(s == static_cast(size / SPI_FLASH_SEC_SIZE)); fclose(f); } - + void save(const char* filename) { FILE* f = fopen(filename, "wb"); @@ -198,16 +209,20 @@ class SpiFlashEmulator { return mTotalTime; } - + void setBounds(uint32_t lowerSector, uint32_t upperSector) { mLowerSectorBound = lowerSector; mUpperSectorBound = upperSector; } - + void failAfter(uint32_t count) { mFailCountdown = count; } + size_t getSectorEraseCount(uint32_t sector) const { + return mEraseCnt[sector]; + } + protected: static size_t getReadOpTime(uint32_t bytes); static size_t getWriteOpTime(uint32_t bytes); @@ -215,6 +230,7 @@ class SpiFlashEmulator std::vector mData; + std::vector mEraseCnt; mutable size_t mReadOps = 0; mutable size_t mWriteOps = 0; @@ -224,7 +240,7 @@ class SpiFlashEmulator mutable size_t mTotalTime = 0; size_t mLowerSectorBound = 0; size_t mUpperSectorBound = 0; - + size_t mFailCountdown = SIZE_MAX; }; diff --git a/components/nvs_flash/test_nvs_host/test_compressed_enum_table.cpp b/components/nvs_flash/test_nvs_host/test_compressed_enum_table.cpp index 225a11c27..a404545c7 100644 --- a/components/nvs_flash/test_nvs_host/test_compressed_enum_table.cpp +++ b/components/nvs_flash/test_nvs_host/test_compressed_enum_table.cpp @@ -53,4 +53,4 @@ TEST_CASE("test if CompressedEnumTable works as expected", "[enumtable]") CHECK(table.data()[0] == 0x93909249); -} \ No newline at end of file +} diff --git a/components/nvs_flash/test_nvs_host/test_fixtures.hpp b/components/nvs_flash/test_nvs_host/test_fixtures.hpp new file mode 100644 index 000000000..473f1da97 --- /dev/null +++ b/components/nvs_flash/test_nvs_host/test_fixtures.hpp @@ -0,0 +1,149 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "nvs_partition.hpp" +#include "nvs_encrypted_partition.hpp" +#include "spi_flash_emulation.h" +#include "nvs.h" + +class PartitionEmulation : public nvs::Partition { +public: + PartitionEmulation(SpiFlashEmulator *spi_flash_emulator, + uint32_t address, + uint32_t size, + const char *partition_name = NVS_DEFAULT_PART_NAME) + : partition_name(partition_name), flash_emu(spi_flash_emulator), address(address), size(size) + { + assert(partition_name); + assert(flash_emu); + assert(size); + } + + const char *get_partition_name() override + { + return partition_name; + } + + esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override + { + if (!flash_emu->read(reinterpret_cast(dst), src_offset, size)) { + return ESP_ERR_FLASH_OP_FAIL; + } + + return ESP_OK; + } + + esp_err_t read(size_t src_offset, void* dst, size_t size) override + { + if (!flash_emu->read(reinterpret_cast(dst), src_offset, size)) { + return ESP_ERR_FLASH_OP_FAIL; + } + + return ESP_OK; + } + + esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override + { + if (!flash_emu->write(dst_offset, reinterpret_cast(src), size)) { + return ESP_ERR_FLASH_OP_FAIL; + } + + return ESP_OK; + } + + esp_err_t write(size_t dst_offset, const void* src, size_t size) override + { + if (!flash_emu->write(dst_offset, reinterpret_cast(src), size)) { + return ESP_ERR_FLASH_OP_FAIL; + } + + return ESP_OK; + } + + esp_err_t erase_range(size_t dst_offset, size_t size) override + { + if (size % SPI_FLASH_SEC_SIZE != 0) { + return ESP_ERR_INVALID_SIZE; + } + + if (dst_offset % SPI_FLASH_SEC_SIZE != 0) { + return ESP_ERR_INVALID_ARG; + } + + size_t start_sector = dst_offset / SPI_FLASH_SEC_SIZE; + size_t num_sectors = size / SPI_FLASH_SEC_SIZE; + for (size_t sector = start_sector; sector < (start_sector + num_sectors); sector++) { + if (!flash_emu->erase(sector)) { + return ESP_ERR_FLASH_OP_FAIL; + } + } + + return ESP_OK; + } + + uint32_t get_address() override + { + return address; + } + + uint32_t get_size() override + { + return size; + } + +private: + const char *partition_name; + + SpiFlashEmulator *flash_emu; + + uint32_t address; + + uint32_t size; +}; + +struct PartitionEmulationFixture { + PartitionEmulationFixture(uint32_t start_sector = 0, + uint32_t sector_size = 1, + const char *partition_name = NVS_DEFAULT_PART_NAME) + : emu(start_sector + sector_size), + part(&emu, start_sector * SPI_FLASH_SEC_SIZE, sector_size * SPI_FLASH_SEC_SIZE, partition_name) { + } + + ~PartitionEmulationFixture() { } + + SpiFlashEmulator emu; + + PartitionEmulation part; +}; + +struct EncryptedPartitionFixture { + EncryptedPartitionFixture(nvs_sec_cfg_t *cfg, + uint32_t start_sector = 0, + uint32_t sector_size = 1, + const char *partition_name = NVS_DEFAULT_PART_NAME) + : esp_partition(), emu(start_sector + sector_size), + part(&esp_partition) { + esp_partition.address = start_sector * SPI_FLASH_SEC_SIZE; + esp_partition.size = sector_size * SPI_FLASH_SEC_SIZE; + strncpy(esp_partition.label, partition_name, PART_NAME_MAX_SIZE); + assert(part.init(cfg) == ESP_OK); + } + + ~EncryptedPartitionFixture() { } + + esp_partition_t esp_partition; + + SpiFlashEmulator emu; + + nvs::NVSEncryptedPartition part; +}; diff --git a/components/nvs_flash/test_nvs_host/test_intrusive_list.cpp b/components/nvs_flash/test_nvs_host/test_intrusive_list.cpp index 979438a0b..dea63f3c3 100644 --- a/components/nvs_flash/test_nvs_host/test_intrusive_list.cpp +++ b/components/nvs_flash/test_nvs_host/test_intrusive_list.cpp @@ -197,8 +197,8 @@ TEST_CASE("can erase all items in the list using clear method", "[list]") TestNode n4("four", 4); TestNode n5("five", 5); TestNode n6("six", 6); - - + + list.push_back(&n1); list.push_back(&n2); list.insert(++list.begin(), &n3); @@ -207,7 +207,6 @@ TEST_CASE("can erase all items in the list using clear method", "[list]") list.insert(list.begin(), &n6); list.clear(); - + REQUIRE(std::begin(list) == std::end(list)); } - diff --git a/components/nvs_flash/test_nvs_host/test_nvs.cpp b/components/nvs_flash/test_nvs_host/test_nvs.cpp index c23f5d661..d8467dfe5 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs.cpp @@ -14,9 +14,21 @@ #include "catch.hpp" #include "nvs.hpp" #include "nvs_test_api.h" +#include "sdkconfig.h" #include "spi_flash_emulation.h" +#include "nvs_partition_manager.hpp" +#include "nvs_partition.hpp" +#include "mbedtls/aes.h" #include #include +#include +#include +#include +#include +#include +#include + +#include "test_fixtures.hpp" #define TEST_ESP_ERR(rc, res) CHECK((rc) == (res)) #define TEST_ESP_OK(rc) CHECK((rc) == ESP_OK) @@ -45,7 +57,7 @@ TEST_CASE("crc32 behaves as expected", "[nvs]") item1.datatype = ItemType::I32; item1.nsIndex = 1; item1.crc32 = 0; - item1.reserved = 0xff; + item1.chunkIndex = 0xff; fill_n(item1.key, sizeof(item1.key), 0xbb); fill_n(item1.data, sizeof(item1.data), 0xaa); @@ -69,20 +81,20 @@ TEST_CASE("crc32 behaves as expected", "[nvs]") CHECK(crc32_1 != item2.calculateCrc32()); } -TEST_CASE("starting with empty flash, page is in uninitialized state", "[nvs]") +TEST_CASE("Page starting with empty flash is in uninitialized state", "[nvs]") { - SpiFlashEmulator emu(1); + PartitionEmulationFixture f; Page page; CHECK(page.state() == Page::PageState::INVALID); - CHECK(page.load(0) == ESP_OK); + CHECK(page.load(&f.part, 0) == ESP_OK); CHECK(page.state() == Page::PageState::UNINITIALIZED); } -TEST_CASE("can distinguish namespaces", "[nvs]") +TEST_CASE("Page can distinguish namespaces", "[nvs]") { - SpiFlashEmulator emu(1); + PartitionEmulationFixture f; Page page; - CHECK(page.load(0) == ESP_OK); + CHECK(page.load(&f.part, 0) == ESP_OK); int32_t val1 = 0x12345678; CHECK(page.writeItem(1, ItemType::I32, "intval1", &val1, sizeof(val1)) == ESP_OK); int32_t val2 = 0x23456789; @@ -94,32 +106,32 @@ TEST_CASE("can distinguish namespaces", "[nvs]") } -TEST_CASE("reading with different type causes type mismatch error", "[nvs]") +TEST_CASE("Page reading with different type causes type mismatch error", "[nvs]") { - SpiFlashEmulator emu(1); + PartitionEmulationFixture f; Page page; - CHECK(page.load(0) == ESP_OK); + CHECK(page.load(&f.part, 0) == ESP_OK); int32_t val = 0x12345678; CHECK(page.writeItem(1, ItemType::I32, "intval1", &val, sizeof(val)) == ESP_OK); CHECK(page.readItem(1, ItemType::U32, "intval1", &val, sizeof(val)) == ESP_ERR_NVS_TYPE_MISMATCH); } -TEST_CASE("when page is erased, it's state becomes UNITIALIZED", "[nvs]") +TEST_CASE("Page when erased, it's state becomes UNITIALIZED", "[nvs]") { - SpiFlashEmulator emu(1); + PartitionEmulationFixture f; Page page; - CHECK(page.load(0) == ESP_OK); + CHECK(page.load(&f.part, 0) == ESP_OK); int32_t val = 0x12345678; CHECK(page.writeItem(1, ItemType::I32, "intval1", &val, sizeof(val)) == ESP_OK); CHECK(page.erase() == ESP_OK); CHECK(page.state() == Page::PageState::UNINITIALIZED); } -TEST_CASE("when writing and erasing, used/erased counts are updated correctly", "[nvs]") +TEST_CASE("Page when writing and erasing, used/erased counts are updated correctly", "[nvs]") { - SpiFlashEmulator emu(1); + PartitionEmulationFixture f; Page page; - CHECK(page.load(0) == ESP_OK); + CHECK(page.load(&f.part, 0) == ESP_OK); CHECK(page.getUsedEntryCount() == 0); CHECK(page.getErasedEntryCount() == 0); uint32_t foo1 = 0; @@ -146,11 +158,11 @@ TEST_CASE("when writing and erasing, used/erased counts are updated correctly", CHECK(page.getErasedEntryCount() == Page::ENTRY_COUNT - 1); } -TEST_CASE("when page is full, adding an element fails", "[nvs]") +TEST_CASE("Page when page is full, adding an element fails", "[nvs]") { - SpiFlashEmulator emu(1); + PartitionEmulationFixture f; Page page; - CHECK(page.load(0) == ESP_OK); + CHECK(page.load(&f.part, 0) == ESP_OK); for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) { char name[16]; snprintf(name, sizeof(name), "i%ld", (long int)i); @@ -159,30 +171,30 @@ TEST_CASE("when page is full, adding an element fails", "[nvs]") CHECK(page.writeItem(1, "foo", 64UL) == ESP_ERR_NVS_PAGE_FULL); } -TEST_CASE("page maintains its seq number") +TEST_CASE("Page maintains its seq number") { - SpiFlashEmulator emu(1); + PartitionEmulationFixture f; { Page page; - CHECK(page.load(0) == ESP_OK); + CHECK(page.load(&f.part, 0) == ESP_OK); CHECK(page.setSeqNumber(123) == ESP_OK); int32_t val = 42; CHECK(page.writeItem(1, ItemType::I32, "dummy", &val, sizeof(val)) == ESP_OK); } { Page page; - CHECK(page.load(0) == ESP_OK); + CHECK(page.load(&f.part, 0) == ESP_OK); uint32_t seqno; CHECK(page.getSeqNumber(seqno) == ESP_OK); CHECK(seqno == 123); } } -TEST_CASE("can write and read variable length data", "[nvs]") +TEST_CASE("Page can write and read variable length data", "[nvs]") { - SpiFlashEmulator emu(1); + PartitionEmulationFixture f; Page page; - CHECK(page.load(0) == ESP_OK); + CHECK(page.load(&f.part, 0) == ESP_OK); const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234"; size_t len = strlen(str); CHECK(page.writeItem(1, "stuff1", 42) == ESP_OK); @@ -212,11 +224,11 @@ TEST_CASE("can write and read variable length data", "[nvs]") CHECK(memcmp(buf, str, strlen(str)) == 0); } -TEST_CASE("different key names are distinguished even if the pointer is the same", "[nvs]") +TEST_CASE("Page different key names are distinguished even if the pointer is the same", "[nvs]") { - SpiFlashEmulator emu(1); + PartitionEmulationFixture f; Page page; - TEST_ESP_OK(page.load(0)); + TEST_ESP_OK(page.load(&f.part, 0)); TEST_ESP_OK(page.writeItem(1, "i1", 1)); TEST_ESP_OK(page.writeItem(1, "i2", 2)); int32_t value; @@ -233,9 +245,9 @@ TEST_CASE("different key names are distinguished even if the pointer is the same TEST_CASE("Page validates key size", "[nvs]") { - SpiFlashEmulator emu(4); + PartitionEmulationFixture f(0, 4); Page page; - TEST_ESP_OK(page.load(0)); + TEST_ESP_OK(page.load(&f.part, 0)); // 16-character key fails TEST_ESP_ERR(page.writeItem(1, "0123456789123456", 1), ESP_ERR_NVS_KEY_TOO_LONG); // 15-character key is okay @@ -244,56 +256,97 @@ TEST_CASE("Page validates key size", "[nvs]") TEST_CASE("Page validates blob size", "[nvs]") { - SpiFlashEmulator emu(4); + PartitionEmulationFixture f(0, 4); Page page; - TEST_ESP_OK(page.load(0)); + TEST_ESP_OK(page.load(&f.part, 0)); - char buf[2048] = { 0 }; + char buf[4096] = { 0 }; // There are two potential errors here: // - not enough space in the page (because one value has been written already) // - value is too long // Check that the second one is actually returned. TEST_ESP_ERR(page.writeItem(1, ItemType::BLOB, "2", buf, Page::ENTRY_COUNT * Page::ENTRY_SIZE), ESP_ERR_NVS_VALUE_TOO_LONG); // Should fail as well - TEST_ESP_ERR(page.writeItem(1, ItemType::BLOB, "2", buf, Page::BLOB_MAX_SIZE + 1), ESP_ERR_NVS_VALUE_TOO_LONG); - TEST_ESP_OK(page.writeItem(1, ItemType::BLOB, "2", buf, Page::BLOB_MAX_SIZE)); + TEST_ESP_ERR(page.writeItem(1, ItemType::BLOB, "2", buf, Page::CHUNK_MAX_SIZE + 1), ESP_ERR_NVS_VALUE_TOO_LONG); + TEST_ESP_OK(page.writeItem(1, ItemType::BLOB, "2", buf, Page::CHUNK_MAX_SIZE)); } TEST_CASE("Page handles invalid CRC of variable length items", "[nvs][cur]") { - SpiFlashEmulator emu(4); + PartitionEmulationFixture f(0, 4); { Page page; - TEST_ESP_OK(page.load(0)); + TEST_ESP_OK(page.load(&f.part, 0)); char buf[128] = {0}; TEST_ESP_OK(page.writeItem(1, ItemType::BLOB, "1", buf, sizeof(buf))); } // corrupt header of the item (64 is the offset of the first item in page) uint32_t overwrite_buf = 0; - emu.write(64, &overwrite_buf, 4); + f.emu.write(64, &overwrite_buf, 4); // load page again { Page page; - TEST_ESP_OK(page.load(0)); + TEST_ESP_OK(page.load(&f.part, 0)); + } +} + +class HashListTestHelper : public HashList +{ + public: + size_t getBlockCount() + { + return mBlockList.size(); + } +}; + +TEST_CASE("HashList is cleaned up as soon as items are erased", "[nvs]") +{ + HashListTestHelper hashlist; + // Add items + const size_t count = 128; + for (size_t i = 0; i < count; ++i) { + char key[16]; + snprintf(key, sizeof(key), "i%ld", (long int)i); + Item item(1, ItemType::U32, 1, key); + hashlist.insert(item, i); + } + INFO("Added " << count << " items, " << hashlist.getBlockCount() << " blocks"); + // Remove them in reverse order + for (size_t i = count; i > 0; --i) { + hashlist.erase(i - 1, true); + } + CHECK(hashlist.getBlockCount() == 0); + // Add again + for (size_t i = 0; i < count; ++i) { + char key[16]; + snprintf(key, sizeof(key), "i%ld", (long int)i); + Item item(1, ItemType::U32, 1, key); + hashlist.insert(item, i); + } + INFO("Added " << count << " items, " << hashlist.getBlockCount() << " blocks"); + // Remove them in the same order + for (size_t i = 0; i < count; ++i) { + hashlist.erase(i, true); } + CHECK(hashlist.getBlockCount() == 0); } TEST_CASE("can init PageManager in empty flash", "[nvs]") { - SpiFlashEmulator emu(4); + PartitionEmulationFixture f(0, 4); PageManager pm; - CHECK(pm.load(0, 4) == ESP_OK); + CHECK(pm.load(&f.part, 0, 4) == ESP_OK); } TEST_CASE("PageManager adds page in the correct order", "[nvs]") { const size_t pageCount = 8; - SpiFlashEmulator emu(pageCount); + PartitionEmulationFixture f(0, pageCount); uint32_t pageNo[pageCount] = { -1U, 50, 11, -1U, 23, 22, 24, 49}; for (uint32_t i = 0; i < pageCount; ++i) { Page p; - p.load(i); + p.load(&f.part, i); if (pageNo[i] != -1U) { p.setSeqNumber(pageNo[i]); p.writeItem(1, "foo", 10U); @@ -301,7 +354,7 @@ TEST_CASE("PageManager adds page in the correct order", "[nvs]") } PageManager pageManager; - CHECK(pageManager.load(0, pageCount) == ESP_OK); + CHECK(pageManager.load(&f.part, 0, pageCount) == ESP_OK); uint32_t lastSeqNo = 0; for (auto it = std::begin(pageManager); it != std::end(pageManager); ++it) { @@ -313,76 +366,77 @@ TEST_CASE("PageManager adds page in the correct order", "[nvs]") TEST_CASE("can init storage in empty flash", "[nvs]") { - SpiFlashEmulator emu(8); - Storage storage; - emu.setBounds(4, 8); + PartitionEmulationFixture f(0, 8); + Storage storage(&f.part); + f.emu.setBounds(4, 8); + cout << "before check" << endl; CHECK(storage.init(4, 4) == ESP_OK); - s_perf << "Time to init empty storage (4 sectors): " << emu.getTotalTime() << " us" << std::endl; + s_perf << "Time to init empty storage (4 sectors): " << f.emu.getTotalTime() << " us" << std::endl; } TEST_CASE("storage doesn't add duplicates within one page", "[nvs]") { - SpiFlashEmulator emu(8); - Storage storage; - emu.setBounds(4, 8); + PartitionEmulationFixture f(0, 8); + Storage storage(&f.part); + f.emu.setBounds(4, 8); CHECK(storage.init(4, 4) == ESP_OK); int bar = 0; - CHECK(storage.writeItem(1, "bar", bar) == ESP_OK); - CHECK(storage.writeItem(1, "bar", bar) == ESP_OK); + CHECK(storage.writeItem(1, "bar", ++bar) == ESP_OK); + CHECK(storage.writeItem(1, "bar", ++bar) == ESP_OK); Page page; - page.load(4); + page.load(&f.part, 4); CHECK(page.getUsedEntryCount() == 1); CHECK(page.getErasedEntryCount() == 1); } TEST_CASE("can write one item a thousand times", "[nvs]") { - SpiFlashEmulator emu(8); - Storage storage; - emu.setBounds(4, 8); + PartitionEmulationFixture f(0, 8); + Storage storage(&f.part); + f.emu.setBounds(4, 8); CHECK(storage.init(4, 4) == ESP_OK); for (size_t i = 0; i < Page::ENTRY_COUNT * 4 * 2; ++i) { REQUIRE(storage.writeItem(1, "i", static_cast(i)) == ESP_OK); } - s_perf << "Time to write one item a thousand times: " << emu.getTotalTime() << " us (" << emu.getEraseOps() << " " << emu.getWriteOps() << " " << emu.getReadOps() << " " << emu.getWriteBytes() << " " << emu.getReadBytes() << ")" << std::endl; + s_perf << "Time to write one item a thousand times: " << f.emu.getTotalTime() << " us (" << f.emu.getEraseOps() << " " << f.emu.getWriteOps() << " " << f.emu.getReadOps() << " " << f.emu.getWriteBytes() << " " << f.emu.getReadBytes() << ")" << std::endl; } TEST_CASE("storage doesn't add duplicates within multiple pages", "[nvs]") { - SpiFlashEmulator emu(8); - Storage storage; - emu.setBounds(4, 8); + PartitionEmulationFixture f(0, 8); + Storage storage(&f.part); + f.emu.setBounds(4, 8); CHECK(storage.init(4, 4) == ESP_OK); int bar = 0; - CHECK(storage.writeItem(1, "bar", bar) == ESP_OK); + CHECK(storage.writeItem(1, "bar", ++bar) == ESP_OK); for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) { - CHECK(storage.writeItem(1, "foo", static_cast(bar)) == ESP_OK); + CHECK(storage.writeItem(1, "foo", static_cast(++bar)) == ESP_OK); } - CHECK(storage.writeItem(1, "bar", bar) == ESP_OK); + CHECK(storage.writeItem(1, "bar", ++bar) == ESP_OK); Page page; - page.load(4); + page.load(&f.part, 4); CHECK(page.findItem(1, itemTypeOf(), "bar") == ESP_ERR_NVS_NOT_FOUND); - page.load(5); + page.load(&f.part, 5); CHECK(page.findItem(1, itemTypeOf(), "bar") == ESP_OK); } TEST_CASE("storage can find items on second page if first is not fully written and has cached search data", "[nvs]") { - SpiFlashEmulator emu(3); - Storage storage; + PartitionEmulationFixture f(0, 3); + Storage storage(&f.part); CHECK(storage.init(0, 3) == ESP_OK); int bar = 0; - uint8_t bigdata[Page::BLOB_MAX_SIZE] = {0}; + uint8_t bigdata[(Page::CHUNK_MAX_SIZE - Page::ENTRY_SIZE)/2] = {0}; // write one big chunk of data ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "1", bigdata, sizeof(bigdata))); // write another big chunk of data ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "2", bigdata, sizeof(bigdata))); - + // write third one; it will not fit into the first page ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "3", bigdata, sizeof(bigdata))); - + size_t size; ESP_ERROR_CHECK(storage.getItemDataSize(0, ItemType::BLOB, "1", size)); CHECK(size == sizeof(bigdata)); @@ -393,9 +447,9 @@ TEST_CASE("storage can find items on second page if first is not fully written a TEST_CASE("can write and read variable length data lots of times", "[nvs]") { - SpiFlashEmulator emu(8); - Storage storage; - emu.setBounds(4, 8); + PartitionEmulationFixture f(0, 8); + Storage storage(&f.part); + f.emu.setBounds(4, 8); CHECK(storage.init(4, 4) == ESP_OK); const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234"; char buf[sizeof(str) + 16]; @@ -413,16 +467,16 @@ TEST_CASE("can write and read variable length data lots of times", "[nvs]") CHECK(storage.readItem(1, ItemType::SZ, "foobaar", buf, sizeof(buf)) == ESP_OK); CHECK(memcmp(buf, str, strlen(str) + 1) == 0); } - s_perf << "Time to write one string and one integer a thousand times: " << emu.getTotalTime() << " us (" << emu.getEraseOps() << " " << emu.getWriteOps() << " " << emu.getReadOps() << " " << emu.getWriteBytes() << " " << emu.getReadBytes() << ")" << std::endl; + s_perf << "Time to write one string and one integer a thousand times: " << f.emu.getTotalTime() << " us (" << f.emu.getEraseOps() << " " << f.emu.getWriteOps() << " " << f.emu.getReadOps() << " " << f.emu.getWriteBytes() << " " << f.emu.getReadBytes() << ")" << std::endl; } TEST_CASE("can get length of variable length data", "[nvs]") { - SpiFlashEmulator emu(8); - emu.randomize(200); - Storage storage; - emu.setBounds(4, 8); + PartitionEmulationFixture f(0, 8); + f.emu.randomize(200); + Storage storage(&f.part); + f.emu.setBounds(4, 8); CHECK(storage.init(4, 4) == ESP_OK); const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234"; size_t len = strlen(str); @@ -439,24 +493,24 @@ TEST_CASE("can get length of variable length data", "[nvs]") TEST_CASE("can create namespaces", "[nvs]") { - SpiFlashEmulator emu(8); - Storage storage; - emu.setBounds(4, 8); + PartitionEmulationFixture f(0, 8); + Storage storage(&f.part); + f.emu.setBounds(4, 8); CHECK(storage.init(4, 4) == ESP_OK); uint8_t nsi; CHECK(storage.createOrOpenNamespace("wifi", false, nsi) == ESP_ERR_NVS_NOT_FOUND); CHECK(storage.createOrOpenNamespace("wifi", true, nsi) == ESP_OK); Page page; - page.load(4); + page.load(&f.part, 4); CHECK(page.findItem(Page::NS_INDEX, ItemType::U8, "wifi") == ESP_OK); } TEST_CASE("storage may become full", "[nvs]") { - SpiFlashEmulator emu(8); - Storage storage; - emu.setBounds(4, 8); + PartitionEmulationFixture f(0, 8); + Storage storage(&f.part); + f.emu.setBounds(4, 8); CHECK(storage.init(4, 4) == ESP_OK); for (size_t i = 0; i < Page::ENTRY_COUNT * 3; ++i) { char name[Item::MAX_KEY_LENGTH + 1]; @@ -468,19 +522,48 @@ TEST_CASE("storage may become full", "[nvs]") TEST_CASE("can modify an item on a page which will be erased", "[nvs]") { - SpiFlashEmulator emu(2); - Storage storage; + PartitionEmulationFixture f(0, 8); + Storage storage(&f.part); CHECK(storage.init(0, 2) == ESP_OK); for (size_t i = 0; i < Page::ENTRY_COUNT * 3 + 1; ++i) { REQUIRE(storage.writeItem(1, "foo", 42U) == ESP_OK); } } +TEST_CASE("erase operations are distributed among sectors", "[nvs]") +{ + const size_t sectors = 6; + PartitionEmulationFixture f(0, sectors); + Storage storage(&f.part); + CHECK(storage.init(0, sectors) == ESP_OK); + + /* Fill some part of storage with static values */ + const size_t static_sectors = 2; + for (size_t i = 0; i < static_sectors * Page::ENTRY_COUNT; ++i) { + char name[Item::MAX_KEY_LENGTH]; + snprintf(name, sizeof(name), "static%d", (int) i); + REQUIRE(storage.writeItem(1, name, i) == ESP_OK); + } + + /* Now perform many write operations */ + const size_t write_ops = 2000; + for (size_t i = 0; i < write_ops; ++i) { + REQUIRE(storage.writeItem(1, "value", i) == ESP_OK); + } + + /* Check that erase counts are distributed between the remaining sectors */ + const size_t max_erase_cnt = write_ops / Page::ENTRY_COUNT / (sectors - static_sectors) + 1; + for (size_t i = 0; i < sectors; ++i) { + auto erase_cnt = f.emu.getSectorEraseCount(i); + INFO("Sector " << i << " erased " << erase_cnt); + CHECK(erase_cnt <= max_erase_cnt); + } +} TEST_CASE("can erase items", "[nvs]") { - SpiFlashEmulator emu(3); - Storage storage; + PartitionEmulationFixture f(0, 8); + Storage storage(&f.part); CHECK(storage.init(0, 3) == ESP_OK); for (size_t i = 0; i < Page::ENTRY_COUNT * 2 - 3; ++i) { char name[Item::MAX_KEY_LENGTH + 1]; @@ -498,22 +581,82 @@ TEST_CASE("can erase items", "[nvs]") CHECK(storage.readItem(3, "key00222", val) == ESP_ERR_NVS_NOT_FOUND); } +TEST_CASE("namespace name is deep copy", "[nvs]") +{ + char ns_name[16]; + strcpy(ns_name, "const_name"); + + nvs_handle_t handle_1; + nvs_handle_t handle_2; + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN); + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + + TEST_ESP_OK(nvs_open("const_name", NVS_READWRITE, &handle_1)); + strcpy(ns_name, "just_kidding"); + + CHECK(nvs_open("just_kidding", NVS_READONLY, &handle_2) == ESP_ERR_NVS_NOT_FOUND); + + nvs_close(handle_1); + nvs_close(handle_2); + + nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME); +} + +TEST_CASE("readonly handle fails on writing", "[nvs]") +{ + PartitionEmulationFixture f(0, 10); + const char* str = "value 0123456789abcdef0123456789abcdef"; + const uint8_t blob[8] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}; + + nvs_handle_t handle_1; + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + + // first, creating namespace... + TEST_ESP_OK(nvs_open("ro_ns", NVS_READWRITE, &handle_1)); + nvs_close(handle_1); + + TEST_ESP_OK(nvs_open("ro_ns", NVS_READONLY, &handle_1)); + TEST_ESP_ERR(nvs_set_i32(handle_1, "key", 47), ESP_ERR_NVS_READ_ONLY); + TEST_ESP_ERR(nvs_set_str(handle_1, "key", str), ESP_ERR_NVS_READ_ONLY); + TEST_ESP_ERR(nvs_set_blob(handle_1, "key", blob, 8), ESP_ERR_NVS_READ_ONLY); + + nvs_close(handle_1); + + // without deinit it affects "nvs api tests" + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); +} + TEST_CASE("nvs api tests", "[nvs]") { - SpiFlashEmulator emu(10); - emu.randomize(100); - - nvs_handle handle_1; + PartitionEmulationFixture f(0, 10); + f.emu.randomize(100); + + nvs_handle_t handle_1; const uint32_t NVS_FLASH_SECTOR = 6; const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; - emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); TEST_ESP_ERR(nvs_open("namespace1", NVS_READWRITE, &handle_1), ESP_ERR_NVS_NOT_INITIALIZED); for (uint16_t i = NVS_FLASH_SECTOR; i init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND); @@ -524,7 +667,7 @@ TEST_CASE("nvs api tests", "[nvs]") TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678)); TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789)); - nvs_handle handle_2; + nvs_handle_t handle_2; TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2)); TEST_ESP_OK(nvs_set_i32(handle_2, "foo", 0x3456789a)); const char* str = "value 0123456789abcdef0123456789abcdef"; @@ -544,11 +687,11 @@ TEST_CASE("nvs api tests", "[nvs]") size_t buf_len_needed; TEST_ESP_OK(nvs_get_str(handle_2, "key", NULL, &buf_len_needed)); CHECK(buf_len_needed == buf_len); - + size_t buf_len_short = buf_len - 1; TEST_ESP_ERR(ESP_ERR_NVS_INVALID_LENGTH, nvs_get_str(handle_2, "key", buf, &buf_len_short)); CHECK(buf_len_short == buf_len); - + size_t buf_len_long = buf_len + 1; TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len_long)); CHECK(buf_len_long == buf_len); @@ -556,51 +699,294 @@ TEST_CASE("nvs api tests", "[nvs]") TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len)); CHECK(0 == strcmp(buf, str)); + nvs_close(handle_1); + nvs_close(handle_2); + + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); +} + +TEST_CASE("deinit partition doesn't affect other partition's open handles", "[nvs]") +{ + const char *OTHER_PARTITION_NAME = "other_part"; + PartitionEmulationFixture f(0, 10); + PartitionEmulationFixture f_other(0, 10, OTHER_PARTITION_NAME); + const char* str = "value 0123456789abcdef0123456789abcdef"; + const uint8_t blob[8] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}; + + nvs_handle_t handle_1; + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + f_other.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f_other.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + + TEST_ESP_OK(nvs_open_from_partition(OTHER_PARTITION_NAME, "ns", NVS_READWRITE, &handle_1)); + + // Deinitializing must not interfere with the open handle from the other partition. + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); + + TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x3456789a)); + nvs_close(handle_1); + + TEST_ESP_OK(nvs_flash_deinit_partition(OTHER_PARTITION_NAME)); +} + +TEST_CASE("nvs iterators tests", "[nvs]") +{ + PartitionEmulationFixture f(0, 5); + + const uint32_t NVS_FLASH_SECTOR = 0; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 5; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + for (uint16_t i = NVS_FLASH_SECTOR; i < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) { + f.emu.erase(i); + } + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + + nvs_iterator_t it; + nvs_entry_info_t info; + nvs_handle handle_1; + nvs_handle handle_2; + const uint32_t blob = 0x11223344; + const char *name_1 = "namespace1"; + const char *name_2 = "namespace2"; + TEST_ESP_OK(nvs_open(name_1, NVS_READWRITE, &handle_1)); + TEST_ESP_OK(nvs_open(name_2, NVS_READWRITE, &handle_2)); + + TEST_ESP_OK(nvs_set_i8(handle_1, "value1", -11)); + TEST_ESP_OK(nvs_set_u8(handle_1, "value2", 11)); + TEST_ESP_OK(nvs_set_i16(handle_1, "value3", 1234)); + TEST_ESP_OK(nvs_set_u16(handle_1, "value4", -1234)); + TEST_ESP_OK(nvs_set_i32(handle_1, "value5", -222)); + TEST_ESP_OK(nvs_set_i32(handle_1, "value6", -222)); + TEST_ESP_OK(nvs_set_i32(handle_1, "value7", -222)); + TEST_ESP_OK(nvs_set_u32(handle_1, "value8", 222)); + TEST_ESP_OK(nvs_set_u32(handle_1, "value9", 222)); + TEST_ESP_OK(nvs_set_str(handle_1, "value10", "foo")); + TEST_ESP_OK(nvs_set_blob(handle_1, "value11", &blob, sizeof(blob))); + TEST_ESP_OK(nvs_set_i32(handle_2, "value1", -111)); + TEST_ESP_OK(nvs_set_i32(handle_2, "value2", -111)); + TEST_ESP_OK(nvs_set_i64(handle_2, "value3", -555)); + TEST_ESP_OK(nvs_set_u64(handle_2, "value4", 555)); + + auto entry_count = [](const char *part, const char *name, nvs_type_t type)-> int { + int count; + nvs_iterator_t it = nvs_entry_find(part, name, type); + for (count = 0; it != nullptr; count++) { + it = nvs_entry_next(it); + } + return count; + }; + + SECTION("Number of entries found for specified namespace and type is correct") + { + CHECK(nvs_entry_find("", NULL, NVS_TYPE_ANY) == NULL); + CHECK(entry_count(NVS_DEFAULT_PART_NAME, NULL, NVS_TYPE_ANY) == 15); + CHECK(entry_count(NVS_DEFAULT_PART_NAME, name_1, NVS_TYPE_ANY) == 11); + CHECK(entry_count(NVS_DEFAULT_PART_NAME, name_1, NVS_TYPE_I32) == 3); + CHECK(entry_count(NVS_DEFAULT_PART_NAME, NULL, NVS_TYPE_I32) == 5); + CHECK(entry_count(NVS_DEFAULT_PART_NAME, NULL, NVS_TYPE_U64) == 1); + } + + SECTION("New entry is not created when existing key-value pair is set") + { + CHECK(entry_count(NVS_DEFAULT_PART_NAME, name_2, NVS_TYPE_ANY) == 4); + TEST_ESP_OK(nvs_set_i32(handle_2, "value1", -222)); + CHECK(entry_count(NVS_DEFAULT_PART_NAME, name_2, NVS_TYPE_ANY) == 4); + } + + SECTION("Number of entries found decrease when entry is erased") + { + CHECK(entry_count(NVS_DEFAULT_PART_NAME, NULL, NVS_TYPE_U64) == 1); + TEST_ESP_OK(nvs_erase_key(handle_2, "value4")); + CHECK(entry_count(NVS_DEFAULT_PART_NAME, "", NVS_TYPE_U64) == 0); + } + + SECTION("All fields of nvs_entry_info_t structure are correct") + { + it = nvs_entry_find(NVS_DEFAULT_PART_NAME, name_1, NVS_TYPE_I32); + CHECK(it != nullptr); + string key = "value5"; + do { + nvs_entry_info(it, &info); + + CHECK(string(name_1) == info.namespace_name); + CHECK(key == info.key); + CHECK(info.type == NVS_TYPE_I32); + + it = nvs_entry_next(it); + key[5]++; + } while (it != NULL); + nvs_release_iterator(it); + } + + SECTION("Entry info is not affected by subsequent erase") + { + nvs_entry_info_t info_after_erase; + + it = nvs_entry_find(NVS_DEFAULT_PART_NAME, name_1, NVS_TYPE_ANY); + nvs_entry_info(it, &info); + TEST_ESP_OK(nvs_erase_key(handle_1, "value1")); + nvs_entry_info(it, &info_after_erase); + CHECK(memcmp(&info, &info_after_erase, sizeof(info)) == 0); + nvs_release_iterator(it); + } + + SECTION("Entry info is not affected by subsequent set") + { + nvs_entry_info_t info_after_set; + + it = nvs_entry_find(NVS_DEFAULT_PART_NAME, name_1, NVS_TYPE_ANY); + nvs_entry_info(it, &info); + TEST_ESP_OK(nvs_set_u8(handle_1, info.key, 44)); + nvs_entry_info(it, &info_after_set); + CHECK(memcmp(&info, &info_after_set, sizeof(info)) == 0); + nvs_release_iterator(it); + } + + + SECTION("Iterating over multiple pages works correctly") + { + nvs_handle handle_3; + const char *name_3 = "namespace3"; + const int entries_created = 250; + + TEST_ESP_OK(nvs_open(name_3, NVS_READWRITE, &handle_3)); + for (size_t i = 0; i < entries_created; i++) { + TEST_ESP_OK(nvs_set_u8(handle_3, to_string(i).c_str(), 123)); + } + + int entries_found = 0; + it = nvs_entry_find(NVS_DEFAULT_PART_NAME, name_3, NVS_TYPE_ANY); + while(it != nullptr) { + entries_found++; + it = nvs_entry_next(it); + } + CHECK(entries_created == entries_found); + + nvs_release_iterator(it); + nvs_close(handle_3); + } + + SECTION("Iterating over multi-page blob works correctly") + { + nvs_handle handle_3; + const char *name_3 = "namespace3"; + const uint8_t multipage_blob[4096 * 2] = { 0 }; + const int NUMBER_OF_ENTRIES_PER_PAGE = 125; + size_t occupied_entries; + + TEST_ESP_OK(nvs_open(name_3, NVS_READWRITE, &handle_3)); + nvs_set_blob(handle_3, "blob", multipage_blob, sizeof(multipage_blob)); + TEST_ESP_OK(nvs_get_used_entry_count(handle_3, &occupied_entries)); + CHECK(occupied_entries > NUMBER_OF_ENTRIES_PER_PAGE * 2); + + CHECK(entry_count(NVS_DEFAULT_PART_NAME, name_3, NVS_TYPE_BLOB) == 1); + + nvs_close(handle_3); + } + + nvs_close(handle_1); + nvs_close(handle_2); + + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); +} + +TEST_CASE("Iterator with not matching type iterates correctly", "[nvs]") +{ + PartitionEmulationFixture f(0, 5); + nvs_iterator_t it; + nvs_handle_t my_handle; + const char* NAMESPACE = "test_ns_4"; + + const uint32_t NVS_FLASH_SECTOR = 0; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 5; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + for (uint16_t i = NVS_FLASH_SECTOR; i < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) { + f.emu.erase(i); + } + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + + // writing string to namespace (a type which spans multiple entries) + TEST_ESP_OK(nvs_open(NAMESPACE, NVS_READWRITE, &my_handle)); + TEST_ESP_OK(nvs_set_str(my_handle, "test-string", "InitString0")); + TEST_ESP_OK(nvs_commit(my_handle)); + nvs_close(my_handle); + + it = nvs_entry_find(NVS_DEFAULT_PART_NAME, NAMESPACE, NVS_TYPE_I32); + CHECK(it == NULL); + + // re-init to trigger cleaning up of broken items -> a corrupted string will be erased + nvs_flash_deinit(); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + + it = nvs_entry_find(NVS_DEFAULT_PART_NAME, NAMESPACE, NVS_TYPE_STR); + CHECK(it != NULL); + nvs_release_iterator(it); + + // without deinit it affects "nvs api tests" + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); } TEST_CASE("wifi test", "[nvs]") { - SpiFlashEmulator emu(10); - emu.randomize(10); - - + PartitionEmulationFixture f(0, 10); + f.emu.randomize(10); + + const uint32_t NVS_FLASH_SECTOR = 5; const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; - emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); - TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); - - nvs_handle misc_handle; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + + nvs_handle_t misc_handle; TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &misc_handle)); char log[33]; size_t log_size = sizeof(log); TEST_ESP_ERR(nvs_get_str(misc_handle, "log", log, &log_size), ESP_ERR_NVS_NOT_FOUND); strcpy(log, "foobarbazfizzz"); TEST_ESP_OK(nvs_set_str(misc_handle, "log", log)); - - nvs_handle net80211_handle; + + nvs_handle_t net80211_handle; TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &net80211_handle)); - + uint8_t opmode = 2; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "wifi.opmode", &opmode), ESP_ERR_NVS_NOT_FOUND); - + TEST_ESP_OK(nvs_set_u8(net80211_handle, "wifi.opmode", opmode)); - + uint8_t country = 0; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "wifi.country", &opmode), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_OK(nvs_set_u8(net80211_handle, "wifi.country", opmode)); - + char ssid[36]; size_t size = sizeof(ssid); TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.ssid", ssid, &size), ESP_ERR_NVS_NOT_FOUND); strcpy(ssid, "my android AP"); TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.ssid", ssid, size)); - + char mac[6]; size = sizeof(mac); TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.mac", mac, &size), ESP_ERR_NVS_NOT_FOUND); memset(mac, 0xab, 6); TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.mac", mac, size)); - + uint8_t authmode = 1; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.authmode", &authmode), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.authmode", authmode)); @@ -616,11 +1002,11 @@ TEST_CASE("wifi test", "[nvs]") TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.pmk", pmk, &size), ESP_ERR_NVS_NOT_FOUND); memset(pmk, 1, size); TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.pmk", pmk, size)); - + uint8_t chan = 1; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.chan", &chan), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.chan", chan)); - + uint8_t autoconn = 1; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "auto.conn", &autoconn), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_OK(nvs_set_u8(net80211_handle, "auto.conn", autoconn)); @@ -638,43 +1024,43 @@ TEST_CASE("wifi test", "[nvs]") uint8_t phym = 3; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.phym", &phym), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.phym", phym)); - + uint8_t phybw = 2; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.phybw", &phybw), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.phybw", phybw)); - + char apsw[2]; size = sizeof(apsw); TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.apsw", apsw, &size), ESP_ERR_NVS_NOT_FOUND); memset(apsw, 0x2, size); TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.apsw", apsw, size)); - + char apinfo[700]; size = sizeof(apinfo); TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.apinfo", apinfo, &size), ESP_ERR_NVS_NOT_FOUND); memset(apinfo, 0, size); TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.apinfo", apinfo, size)); - + size = sizeof(ssid); TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.ssid", ssid, &size), ESP_ERR_NVS_NOT_FOUND); strcpy(ssid, "ESP_A2F340"); TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.ssid", ssid, size)); - + size = sizeof(mac); TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.mac", mac, &size), ESP_ERR_NVS_NOT_FOUND); memset(mac, 0xac, 6); TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.mac", mac, size)); - + size = sizeof(pswd); TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.passwd", pswd, &size), ESP_ERR_NVS_NOT_FOUND); strcpy(pswd, ""); TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.passwd", pswd, size)); - + size = sizeof(pmk); TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.pmk", pmk, &size), ESP_ERR_NVS_NOT_FOUND); memset(pmk, 1, size); TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.pmk", pmk, size)); - + chan = 6; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.chan", &chan), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.chan", chan)); @@ -682,63 +1068,133 @@ TEST_CASE("wifi test", "[nvs]") authmode = 0; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.authmode", &authmode), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.authmode", authmode)); - + uint8_t hidden = 0; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.hidden", &hidden), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.hidden", hidden)); - + uint8_t max_conn = 4; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.max.conn", &max_conn), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.max.conn", max_conn)); - + uint8_t bcn_interval = 2; TEST_ESP_ERR(nvs_get_u8(net80211_handle, "bcn_interval", &bcn_interval), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_OK(nvs_set_u8(net80211_handle, "bcn_interval", bcn_interval)); - - s_perf << "Time to simulate nvs init with wifi libs: " << emu.getTotalTime() << " us (" << emu.getEraseOps() << "E " << emu.getWriteOps() << "W " << emu.getReadOps() << "R " << emu.getWriteBytes() << "Wb " << emu.getReadBytes() << "Rb)" << std::endl; + s_perf << "Time to simulate nvs init with wifi libs: " << f.emu.getTotalTime() << " us (" << f.emu.getEraseOps() << "E " << f.emu.getWriteOps() << "W " << f.emu.getReadOps() << "R " << f.emu.getWriteBytes() << "Wb " << f.emu.getReadBytes() << "Rb)" << std::endl; + + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); } +TEST_CASE("writing the identical content does not write or erase", "[nvs]") +{ + PartitionEmulationFixture f(0, 20); + + const uint32_t NVS_FLASH_SECTOR = 5; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 10; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + + nvs_handle misc_handle; + TEST_ESP_OK(nvs_open("test", NVS_READWRITE, &misc_handle)); + + // Test writing a u8 twice, then changing it + nvs_set_u8(misc_handle, "test_u8", 8); + f.emu.clearStats(); + nvs_set_u8(misc_handle, "test_u8", 8); + CHECK(f.emu.getWriteOps() == 0); + CHECK(f.emu.getEraseOps() == 0); + CHECK(f.emu.getReadOps() != 0); + f.emu.clearStats(); + nvs_set_u8(misc_handle, "test_u8", 9); + CHECK(f.emu.getWriteOps() != 0); + CHECK(f.emu.getReadOps() != 0); + + // Test writing a string twice, then changing it + static const char *test[2] = {"Hello world.", "Hello world!"}; + nvs_set_str(misc_handle, "test_str", test[0]); + f.emu.clearStats(); + nvs_set_str(misc_handle, "test_str", test[0]); + CHECK(f.emu.getWriteOps() == 0); + CHECK(f.emu.getEraseOps() == 0); + CHECK(f.emu.getReadOps() != 0); + f.emu.clearStats(); + nvs_set_str(misc_handle, "test_str", test[1]); + CHECK(f.emu.getWriteOps() != 0); + CHECK(f.emu.getReadOps() != 0); + + // Test writing a multi-page blob, then changing it + uint8_t blob[Page::CHUNK_MAX_SIZE * 3] = {0}; + memset(blob, 1, sizeof(blob)); + nvs_set_blob(misc_handle, "test_blob", blob, sizeof(blob)); + f.emu.clearStats(); + nvs_set_blob(misc_handle, "test_blob", blob, sizeof(blob)); + CHECK(f.emu.getWriteOps() == 0); + CHECK(f.emu.getEraseOps() == 0); + CHECK(f.emu.getReadOps() != 0); + blob[sizeof(blob) - 1]++; + f.emu.clearStats(); + nvs_set_blob(misc_handle, "test_blob", blob, sizeof(blob)); + CHECK(f.emu.getWriteOps() != 0); + CHECK(f.emu.getReadOps() != 0); + + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); +} TEST_CASE("can init storage from flash with random contents", "[nvs]") { - SpiFlashEmulator emu(10); - emu.randomize(42); - - nvs_handle handle; + PartitionEmulationFixture f(0, 10); + f.emu.randomize(42); + + nvs_handle_t handle; const uint32_t NVS_FLASH_SECTOR = 5; const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; - emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); - TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); - + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &handle)); - + uint8_t opmode = 2; if (nvs_get_u8(handle, "wifi.opmode", &opmode) != ESP_OK) { TEST_ESP_OK(nvs_set_u8(handle, "wifi.opmode", opmode)); } + + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); } -TEST_CASE("nvs api tests, starting with random data in flash", "[nvs][.][long]") +TEST_CASE("nvs api tests, starting with random data in flash", "[nvs][long]") { - for (size_t count = 0; count < 10000; ++count) { - SpiFlashEmulator emu(10); - emu.randomize(static_cast(count)); - + const size_t testIters = 3000; + int lastPercent = -1; + for (size_t count = 0; count < testIters; ++count) { + int percentDone = (int) (count * 100 / testIters); + if (percentDone != lastPercent) { + lastPercent = percentDone; + printf("%d%%\n", percentDone); + } + PartitionEmulationFixture f(0, 10); + f.emu.randomize(static_cast(count)); + const uint32_t NVS_FLASH_SECTOR = 6; const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; - emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); - - TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); - - nvs_handle handle_1; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + + nvs_handle_t handle_1; TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND); - + TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1)); TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678)); for (size_t i = 0; i < 500; ++i) { - nvs_handle handle_2; + nvs_handle_t handle_2; TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2)); TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789 % (i + 1))); TEST_ESP_OK(nvs_set_i32(handle_2, "foo", static_cast(i))); @@ -746,38 +1202,42 @@ TEST_CASE("nvs api tests, starting with random data in flash", "[nvs][.][long]") char str_buf[128]; snprintf(str_buf, sizeof(str_buf), str, i + count * 1024); TEST_ESP_OK(nvs_set_str(handle_2, "key", str_buf)); - + int32_t v1; TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1)); CHECK(0x23456789 % (i + 1) == v1); - + int32_t v2; TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2)); CHECK(static_cast(i) == v2); - + char buf[128]; size_t buf_len = sizeof(buf); - + TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len)); - + CHECK(0 == strcmp(buf, str_buf)); nvs_close(handle_2); } nvs_close(handle_1); } -} + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); +} extern "C" void nvs_dump(const char *partName); class RandomTest { - - static const size_t nKeys = 9; + + static const size_t nKeys = 11; int32_t v1 = 0, v2 = 0; uint64_t v3 = 0, v4 = 0; static const size_t strBufLen = 1024; + static const size_t smallBlobLen = Page::CHUNK_MAX_SIZE / 3; + static const size_t largeBlobLen = Page::CHUNK_MAX_SIZE * 3; char v5[strBufLen], v6[strBufLen], v7[strBufLen], v8[strBufLen], v9[strBufLen]; + uint8_t v10[smallBlobLen], v11[largeBlobLen]; bool written[nKeys]; - + public: RandomTest() { @@ -785,17 +1245,17 @@ class RandomTest { } template - esp_err_t doRandomThings(nvs_handle handle, TGen gen, size_t& count) { - - const char* keys[] = {"foo", "bar", "longkey_0123456", "another key", "param1", "param2", "param3", "param4", "param5"}; - const ItemType types[] = {ItemType::I32, ItemType::I32, ItemType::U64, ItemType::U64, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ}; - - void* values[] = {&v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8, &v9}; - + esp_err_t doRandomThings(nvs_handle_t handle, TGen gen, size_t& count) { + + const char* keys[] = {"foo", "bar", "longkey_0123456", "another key", "param1", "param2", "param3", "param4", "param5", "singlepage", "multipage"}; + const ItemType types[] = {ItemType::I32, ItemType::I32, ItemType::U64, ItemType::U64, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::BLOB, ItemType::BLOB}; + + void* values[] = {&v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8, &v9, &v10, &v11}; + const size_t nKeys = sizeof(keys) / sizeof(keys[0]); static_assert(nKeys == sizeof(types) / sizeof(types[0]), ""); static_assert(nKeys == sizeof(values) / sizeof(values[0]), ""); - + auto randomRead = [&](size_t index) -> esp_err_t { switch (types[index]) { case ItemType::I32: @@ -814,7 +1274,7 @@ class RandomTest { } break; } - + case ItemType::U64: { uint64_t val; @@ -831,7 +1291,7 @@ class RandomTest { } break; } - + case ItemType::SZ: { char buf[strBufLen]; @@ -849,19 +1309,47 @@ class RandomTest { } break; } - + + case ItemType::BLOB: + { + uint32_t blobBufLen = 0; + if(strncmp(keys[index],"singlepage", sizeof("singlepage")) == 0) { + blobBufLen = smallBlobLen ; + } else { + blobBufLen = largeBlobLen ; + + } + uint8_t buf[blobBufLen]; + memset(buf, 0, blobBufLen); + + size_t len = blobBufLen; + auto err = nvs_get_blob(handle, keys[index], buf, &len); + if (err == ESP_ERR_FLASH_OP_FAIL) { + return err; + } + if (!written[index]) { + REQUIRE(err == ESP_ERR_NVS_NOT_FOUND); + } + else { + REQUIRE(err == ESP_OK); + REQUIRE(memcmp(buf, reinterpret_cast(values[index]), blobBufLen) == 0); + } + break; + } + + default: assert(0); } return ESP_OK; }; - + auto randomWrite = [&](size_t index) -> esp_err_t { switch (types[index]) { case ItemType::I32: { int32_t val = static_cast(gen()); - + auto err = nvs_set_i32(handle, keys[index], val); if (err == ESP_ERR_FLASH_OP_FAIL) { return err; @@ -876,11 +1364,11 @@ class RandomTest { *reinterpret_cast(values[index]) = val; break; } - + case ItemType::U64: { uint64_t val = static_cast(gen()); - + auto err = nvs_set_u64(handle, keys[index], val); if (err == ESP_ERR_FLASH_OP_FAIL) { return err; @@ -895,19 +1383,19 @@ class RandomTest { *reinterpret_cast(values[index]) = val; break; } - + case ItemType::SZ: { char buf[strBufLen]; size_t len = strBufLen; - + size_t strLen = gen() % (strBufLen - 1); std::generate_n(buf, strLen, [&]() -> char { const char c = static_cast(gen() % 127); return (c < 32) ? 32 : c; }); buf[strLen] = 0; - + auto err = nvs_set_str(handle, keys[index], buf); if (err == ESP_ERR_FLASH_OP_FAIL) { return err; @@ -922,23 +1410,53 @@ class RandomTest { strncpy(reinterpret_cast(values[index]), buf, strBufLen); break; } - + + case ItemType::BLOB: + { + uint32_t blobBufLen = 0; + if(strncmp(keys[index],"singlepage", sizeof("singlepage")) == 0) { + blobBufLen = smallBlobLen ; + } else { + blobBufLen = largeBlobLen ; + } + uint8_t buf[blobBufLen]; + memset(buf, 0, blobBufLen); + size_t blobLen = gen() % blobBufLen; + std::generate_n(buf, blobLen, [&]() -> uint8_t { + return static_cast(gen() % 256); + }); + + auto err = nvs_set_blob(handle, keys[index], buf, blobLen); + if (err == ESP_ERR_FLASH_OP_FAIL) { + return err; + } + if (err == ESP_ERR_NVS_REMOVE_FAILED) { + written[index] = true; + memcpy(reinterpret_cast(values[index]), buf, blobBufLen); + return ESP_ERR_FLASH_OP_FAIL; + } + REQUIRE(err == ESP_OK); + written[index] = true; + memcpy(reinterpret_cast(values[index]), buf, blobBufLen); + break; + } + default: assert(0); } return ESP_OK; }; - - + + for (; count != 0; --count) { - size_t index = gen() % nKeys; + size_t index = gen() % (nKeys); switch (gen() % 3) { case 0: // read, 1/3 if (randomRead(index) == ESP_ERR_FLASH_OP_FAIL) { return ESP_ERR_FLASH_OP_FAIL; } break; - + default: // write, 2/3 if (randomWrite(index) == ESP_ERR_FLASH_OP_FAIL) { return ESP_ERR_FLASH_OP_FAIL; @@ -948,8 +1466,20 @@ class RandomTest { } return ESP_OK; } -}; + esp_err_t handleExternalWriteAtIndex(uint8_t index, const void* value, const size_t len ) { + if(index == 9) { /* This is only done for small-page blobs for now*/ + if(len > smallBlobLen) { + return ESP_FAIL; + } + memcpy(v10, value, len); + written[index] = true; + return ESP_OK; + } else { + return ESP_FAIL; + } + } +}; TEST_CASE("monkey test", "[nvs][monkey]") { @@ -957,49 +1487,54 @@ TEST_CASE("monkey test", "[nvs][monkey]") std::mt19937 gen(rd()); uint32_t seed = 3; gen.seed(seed); - - SpiFlashEmulator emu(10); - emu.randomize(seed); - emu.clearStats(); - - const uint32_t NVS_FLASH_SECTOR = 6; - const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; - emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); - - TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); - - nvs_handle handle; + + PartitionEmulationFixture f(0, 10); + f.emu.randomize(seed); + f.emu.clearStats(); + + const uint32_t NVS_FLASH_SECTOR = 2; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 8; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + + nvs_handle_t handle; TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); RandomTest test; size_t count = 1000; CHECK(test.doRandomThings(handle, gen, count) == ESP_OK); - - s_perf << "Monkey test: nErase=" << emu.getEraseOps() << " nWrite=" << emu.getWriteOps() << std::endl; + + s_perf << "Monkey test: nErase=" << f.emu.getEraseOps() << " nWrite=" << f.emu.getWriteOps() << std::endl; + + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); } -TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey]") +TEST_CASE("test recovery from sudden poweroff", "[long][nvs][recovery][monkey]") { std::random_device rd; std::mt19937 gen(rd()); uint32_t seed = 3; gen.seed(seed); const size_t iter_count = 2000; - - SpiFlashEmulator emu(10); - - const uint32_t NVS_FLASH_SECTOR = 6; - const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; - emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); - + + PartitionEmulationFixture f(0, 10); + + const uint32_t NVS_FLASH_SECTOR = 2; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 8; + + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + size_t totalOps = 0; int lastPercent = -1; for (uint32_t errDelay = 0; ; ++errDelay) { INFO(errDelay); - emu.randomize(seed); - emu.clearStats(); - emu.failAfter(errDelay); + f.emu.randomize(seed); + f.emu.clearStats(); + f.emu.failAfter(errDelay); RandomTest test; - + if (totalOps != 0) { int percent = errDelay * 100 / totalOps; if (percent > lastPercent) { @@ -1007,12 +1542,14 @@ TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey lastPercent = percent; } } - - nvs_handle handle; + + nvs_handle_t handle; size_t count = iter_count; - if (nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK) { + if (NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK) { if (nvs_open("namespace1", NVS_READWRITE, &handle) == ESP_OK) { if(test.doRandomThings(handle, gen, count) != ESP_ERR_FLASH_OP_FAIL) { nvs_close(handle); @@ -1020,9 +1557,12 @@ TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey } nvs_close(handle); } + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); } - - TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); + + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); auto res = test.doRandomThings(handle, gen, count); if (res != ESP_OK) { @@ -1030,35 +1570,40 @@ TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey CHECK(0); } nvs_close(handle); - totalOps = emu.getEraseOps() + emu.getWriteBytes() / 4; + totalOps = f.emu.getEraseOps() + f.emu.getWriteBytes() / 4; + + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); } } - TEST_CASE("test for memory leaks in open/set", "[leaks]") { - SpiFlashEmulator emu(10); + PartitionEmulationFixture f(0, 10); const uint32_t NVS_FLASH_SECTOR = 6; const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; - emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); - TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); - + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + for (int i = 0; i < 100000; ++i) { - nvs_handle light_handle = 0; + nvs_handle_t light_handle = 0; char lightbulb[1024] = {12, 13, 14, 15, 16}; TEST_ESP_OK(nvs_open("light", NVS_READWRITE, &light_handle)); TEST_ESP_OK(nvs_set_blob(light_handle, "key", lightbulb, sizeof(lightbulb))); TEST_ESP_OK(nvs_commit(light_handle)); nvs_close(light_handle); } + + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); } TEST_CASE("duplicate items are removed", "[nvs][dupes]") { - SpiFlashEmulator emu(3); + PartitionEmulationFixture f(0, 3); { // create one item nvs::Page p; - p.load(0); + p.load(&f.part, 0); p.writeItem(1, "opmode", 3); } { @@ -1066,14 +1611,14 @@ TEST_CASE("duplicate items are removed", "[nvs][dupes]") nvs::Item item(1, ItemType::U8, 1, "opmode"); item.data[0] = 2; item.crc32 = item.calculateCrc32(); - emu.write(3 * 32, reinterpret_cast(&item), sizeof(item)); - emu.write(4 * 32, reinterpret_cast(&item), sizeof(item)); + f.emu.write(3 * 32, reinterpret_cast(&item), sizeof(item)); + f.emu.write(4 * 32, reinterpret_cast(&item), sizeof(item)); uint32_t mask = 0xFFFFFFEA; - emu.write(32, &mask, 4); + f.emu.write(32, &mask, 4); } { // load page and check that second item persists - nvs::Storage s; + nvs::Storage s(&f.part); s.init(0, 3); uint8_t val; ESP_ERROR_CHECK(s.readItem(1, "opmode", val)); @@ -1081,7 +1626,7 @@ TEST_CASE("duplicate items are removed", "[nvs][dupes]") } { Page p; - p.load(0); + p.load(&f.part, 0); CHECK(p.getErasedEntryCount() == 2); CHECK(p.getUsedEntryCount() == 1); } @@ -1089,30 +1634,30 @@ TEST_CASE("duplicate items are removed", "[nvs][dupes]") TEST_CASE("recovery after failure to write data", "[nvs]") { - SpiFlashEmulator emu(3); + PartitionEmulationFixture f(0, 3); const char str[] = "value 0123456789abcdef012345678value 0123456789abcdef012345678"; // make flash write fail exactly in Page::writeEntryData - emu.failAfter(17); + f.emu.failAfter(17); { - Storage storage; + Storage storage(&f.part); TEST_ESP_OK(storage.init(0, 3)); - + TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_FLASH_OP_FAIL); - + // check that repeated operations cause an error TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_NVS_INVALID_STATE); - + uint8_t val; TEST_ESP_ERR(storage.readItem(1, ItemType::U8, "key", &val, sizeof(val)), ESP_ERR_NVS_NOT_FOUND); } { // load page and check that data was erased Page p; - p.load(0); + p.load(&f.part, 0); CHECK(p.getErasedEntryCount() == 3); CHECK(p.getUsedEntryCount() == 0); - + // try to write again TEST_ESP_OK(p.writeItem(1, ItemType::SZ, "key", str, strlen(str))); } @@ -1120,25 +1665,25 @@ TEST_CASE("recovery after failure to write data", "[nvs]") TEST_CASE("crc errors in item header are handled", "[nvs]") { - SpiFlashEmulator emu(3); - Storage storage; + PartitionEmulationFixture f(0, 3); + Storage storage(&f.part); // prepare some data TEST_ESP_OK(storage.init(0, 3)); TEST_ESP_OK(storage.writeItem(0, "ns1", static_cast(1))); TEST_ESP_OK(storage.writeItem(1, "value1", static_cast(1))); TEST_ESP_OK(storage.writeItem(1, "value2", static_cast(2))); - + // corrupt item header uint32_t val = 0; - emu.write(32 * 3, &val, 4); - + f.emu.write(32 * 3, &val, 4); + // check that storage can recover TEST_ESP_OK(storage.init(0, 3)); TEST_ESP_OK(storage.readItem(1, "value2", val)); CHECK(val == 2); // check that the corrupted item is no longer present TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, storage.readItem(1, "value1", val)); - + // add more items to make the page full for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) { char item_name[Item::MAX_KEY_LENGTH + 1]; @@ -1148,8 +1693,8 @@ TEST_CASE("crc errors in item header are handled", "[nvs]") // corrupt another item on the full page val = 0; - emu.write(32 * 4, &val, 4); - + f.emu.write(32 * 4, &val, 4); + // check that storage can recover TEST_ESP_OK(storage.init(0, 3)); // check that the corrupted item is no longer present @@ -1158,13 +1703,13 @@ TEST_CASE("crc errors in item header are handled", "[nvs]") TEST_CASE("crc error in variable length item is handled", "[nvs]") { - SpiFlashEmulator emu(3); + PartitionEmulationFixture f(0, 3); const uint64_t before_val = 0xbef04e; const uint64_t after_val = 0xaf7e4; // write some data { Page p; - p.load(0); + p.load(&f.part, 0); TEST_ESP_OK(p.writeItem(0, "before", before_val)); const char* str = "foobar"; TEST_ESP_OK(p.writeItem(0, ItemType::SZ, "key", str, strlen(str))); @@ -1172,13 +1717,13 @@ TEST_CASE("crc error in variable length item is handled", "[nvs]") } // corrupt some data uint32_t w; - CHECK(emu.read(&w, 32 * 3 + 8, sizeof(w))); + CHECK(f.emu.read(&w, 32 * 3 + 8, sizeof(w))); w &= 0xf000000f; - CHECK(emu.write(32 * 3 + 8, &w, sizeof(w))); + CHECK(f.emu.write(32 * 3 + 8, &w, sizeof(w))); // load and check { Page p; - p.load(0); + p.load(&f.part, 0); CHECK(p.getUsedEntryCount() == 2); CHECK(p.getErasedEntryCount() == 2); @@ -1194,16 +1739,16 @@ TEST_CASE("crc error in variable length item is handled", "[nvs]") TEST_CASE("read/write failure (TW8406)", "[nvs]") { - SpiFlashEmulator emu(3); - nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3); + PartitionEmulationFixture f(0, 3); + NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3); for (int attempts = 0; attempts < 3; ++attempts) { int i = 0; - nvs_handle light_handle = 0; + nvs_handle_t light_handle = 0; char key[15] = {0}; char data[76] = {12, 13, 14, 15, 16}; uint8_t number = 20; size_t data_len = sizeof(data); - + ESP_ERROR_CHECK(nvs_open("LIGHT", NVS_READWRITE, &light_handle)); ESP_ERROR_CHECK(nvs_set_u8(light_handle, "RecordNum", number)); for (i = 0; i < number; ++i) { @@ -1211,7 +1756,7 @@ TEST_CASE("read/write failure (TW8406)", "[nvs]") ESP_ERROR_CHECK(nvs_set_blob(light_handle, key, data, sizeof(data))); } nvs_commit(light_handle); - + uint8_t get_number = 0; ESP_ERROR_CHECK(nvs_get_u8(light_handle, "RecordNum", &get_number)); REQUIRE(number == get_number); @@ -1222,38 +1767,44 @@ TEST_CASE("read/write failure (TW8406)", "[nvs]") } nvs_close(light_handle); } + + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); } TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]") { - const size_t blob_size = Page::BLOB_MAX_SIZE; + const size_t blob_size = Page::CHUNK_MAX_SIZE; uint8_t blob[blob_size] = {0}; - SpiFlashEmulator emu(5); - TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 5) ); - nvs_handle handle; + PartitionEmulationFixture f(0, 8); + TEST_ESP_OK( NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 5) ); + nvs_handle_t handle; TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) ); // Fill first page TEST_ESP_OK( nvs_set_blob(handle, "1a", blob, blob_size) ); - TEST_ESP_OK( nvs_set_blob(handle, "1b", blob, blob_size) ); // Fill second page TEST_ESP_OK( nvs_set_blob(handle, "2a", blob, blob_size) ); - TEST_ESP_OK( nvs_set_blob(handle, "2b", blob, blob_size) ); // Fill third page TEST_ESP_OK( nvs_set_blob(handle, "3a", blob, blob_size) ); - TEST_ESP_OK( nvs_set_blob(handle, "3b", blob, blob_size) ); TEST_ESP_OK( nvs_commit(handle) ); nvs_close(handle); + TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME)); // first two pages are now full, third one is writable, last two are empty // init should fail - TEST_ESP_ERR( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3), ESP_ERR_NVS_NO_FREE_PAGES ); + TEST_ESP_ERR( NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3), + ESP_ERR_NVS_NO_FREE_PAGES ); + + // in case this test fails, to not affect other tests + nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME); } TEST_CASE("multiple partitions access check", "[nvs]") { SpiFlashEmulator emu(10); - TEST_ESP_OK( nvs_flash_init_custom("nvs1", 0, 5) ); - TEST_ESP_OK( nvs_flash_init_custom("nvs2", 5, 5) ); - nvs_handle handle1, handle2; + PartitionEmulation p0(&emu, 0 * SPI_FLASH_SEC_SIZE, 5 * SPI_FLASH_SEC_SIZE, "nvs1"); + PartitionEmulation p1(&emu, 5 * SPI_FLASH_SEC_SIZE, 5 * SPI_FLASH_SEC_SIZE, "nvs2"); + TEST_ESP_OK( NVSPartitionManager::get_instance()->init_custom(&p0, 0, 5) ); + TEST_ESP_OK( NVSPartitionManager::get_instance()->init_custom(&p1, 5, 5) ); + nvs_handle_t handle1, handle2; TEST_ESP_OK( nvs_open_from_partition("nvs1", "test", NVS_READWRITE, &handle1) ); TEST_ESP_OK( nvs_open_from_partition("nvs2", "test", NVS_READWRITE, &handle2) ); TEST_ESP_OK( nvs_set_i32(handle1, "foo", 0xdeadbeef)); @@ -1263,15 +1814,18 @@ TEST_CASE("multiple partitions access check", "[nvs]") TEST_ESP_OK( nvs_get_i32(handle2, "foo", &v2)); CHECK(v1 == 0xdeadbeef); CHECK(v2 == 0xcafebabe); + + TEST_ESP_OK(nvs_flash_deinit_partition(p0.get_partition_name())); + TEST_ESP_OK(nvs_flash_deinit_partition(p1.get_partition_name())); } TEST_CASE("nvs page selection takes into account free entries also not just erased entries", "[nvs]") { - const size_t blob_size = Page::BLOB_MAX_SIZE; + const size_t blob_size = Page::CHUNK_MAX_SIZE/2; uint8_t blob[blob_size] = {0}; - SpiFlashEmulator emu(3); - TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3) ); - nvs_handle handle; + PartitionEmulationFixture f(0, 3); + TEST_ESP_OK( NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3) ); + nvs_handle_t handle; TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) ); // Fill first page TEST_ESP_OK( nvs_set_blob(handle, "1a", blob, blob_size/3) ); @@ -1284,8 +1838,1689 @@ TEST_CASE("nvs page selection takes into account free entries also not just eras TEST_ESP_OK( nvs_set_blob(handle, "3a", blob, 4) ); TEST_ESP_OK( nvs_commit(handle) ); nvs_close(handle); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +TEST_CASE("calculate used and free space", "[nvs]") +{ + PartitionEmulationFixture f(0, 6); + nvs_flash_deinit(); + TEST_ESP_ERR(nvs_get_stats(NULL, NULL), ESP_ERR_INVALID_ARG); + nvs_stats_t stat1; + nvs_stats_t stat2; + TEST_ESP_ERR(nvs_get_stats(NULL, &stat1), ESP_ERR_NVS_NOT_INITIALIZED); + CHECK(stat1.free_entries == 0); + CHECK(stat1.namespace_count == 0); + CHECK(stat1.total_entries == 0); + CHECK(stat1.used_entries == 0); + + nvs_handle_t handle = 0; + size_t h_count_entries; + TEST_ESP_ERR(nvs_get_used_entry_count(handle, &h_count_entries), ESP_ERR_NVS_INVALID_HANDLE); + CHECK(h_count_entries == 0); + + // init nvs + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 6)); + + TEST_ESP_ERR(nvs_get_used_entry_count(handle, &h_count_entries), ESP_ERR_NVS_INVALID_HANDLE); + CHECK(h_count_entries == 0); + + Page p; + // after erase. empty partition + TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); + CHECK(stat1.free_entries != 0); + CHECK(stat1.namespace_count == 0); + CHECK(stat1.total_entries == 6 * p.ENTRY_COUNT); + CHECK(stat1.used_entries == 0); + + // create namespace test_k1 + nvs_handle_t handle_1; + TEST_ESP_OK(nvs_open("test_k1", NVS_READWRITE, &handle_1)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat2)); + CHECK(stat2.free_entries + 1 == stat1.free_entries); + CHECK(stat2.namespace_count == 1); + CHECK(stat2.total_entries == stat1.total_entries); + CHECK(stat2.used_entries == 1); + + // create pair key-value com + TEST_ESP_OK(nvs_set_i32(handle_1, "com", 0x12345678)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); + CHECK(stat1.free_entries + 1 == stat2.free_entries); + CHECK(stat1.namespace_count == 1); + CHECK(stat1.total_entries == stat2.total_entries); + CHECK(stat1.used_entries == 2); + + // change value in com + TEST_ESP_OK(nvs_set_i32(handle_1, "com", 0x01234567)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat2)); + CHECK(stat2.free_entries == stat1.free_entries); + CHECK(stat2.namespace_count == 1); + CHECK(stat2.total_entries != 0); + CHECK(stat2.used_entries == 2); + + // create pair key-value ru + TEST_ESP_OK(nvs_set_i32(handle_1, "ru", 0x00FF00FF)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); + CHECK(stat1.free_entries + 1 == stat2.free_entries); + CHECK(stat1.namespace_count == 1); + CHECK(stat1.total_entries != 0); + CHECK(stat1.used_entries == 3); + + // amount valid pair in namespace 1 + size_t h1_count_entries; + TEST_ESP_OK(nvs_get_used_entry_count(handle_1, &h1_count_entries)); + CHECK(h1_count_entries == 2); + + nvs_handle_t handle_2; + // create namespace test_k2 + TEST_ESP_OK(nvs_open("test_k2", NVS_READWRITE, &handle_2)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat2)); + CHECK(stat2.free_entries + 1 == stat1.free_entries); + CHECK(stat2.namespace_count == 2); + CHECK(stat2.total_entries == stat1.total_entries); + CHECK(stat2.used_entries == 4); + + // create pair key-value + TEST_ESP_OK(nvs_set_i32(handle_2, "su1", 0x00000001)); + TEST_ESP_OK(nvs_set_i32(handle_2, "su2", 0x00000002)); + TEST_ESP_OK(nvs_set_i32(handle_2, "sus", 0x00000003)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); + CHECK(stat1.free_entries + 3 == stat2.free_entries); + CHECK(stat1.namespace_count == 2); + CHECK(stat1.total_entries == stat2.total_entries); + CHECK(stat1.used_entries == 7); + + CHECK(stat1.total_entries == (stat1.used_entries + stat1.free_entries)); + + // amount valid pair in namespace 2 + size_t h2_count_entries; + TEST_ESP_OK(nvs_get_used_entry_count(handle_2, &h2_count_entries)); + CHECK(h2_count_entries == 3); + + CHECK(stat1.used_entries == (h1_count_entries + h2_count_entries + stat1.namespace_count)); + + nvs_close(handle_1); + nvs_close(handle_2); + + size_t temp = h2_count_entries; + TEST_ESP_ERR(nvs_get_used_entry_count(handle_1, &h2_count_entries), ESP_ERR_NVS_INVALID_HANDLE); + CHECK(h2_count_entries == 0); + h2_count_entries = temp; + TEST_ESP_ERR(nvs_get_used_entry_count(handle_1, NULL), ESP_ERR_INVALID_ARG); + + nvs_handle_t handle_3; + // create namespace test_k3 + TEST_ESP_OK(nvs_open("test_k3", NVS_READWRITE, &handle_3)); + TEST_ESP_OK(nvs_get_stats(NULL, &stat2)); + CHECK(stat2.free_entries + 1 == stat1.free_entries); + CHECK(stat2.namespace_count == 3); + CHECK(stat2.total_entries == stat1.total_entries); + CHECK(stat2.used_entries == 8); + + // create pair blobs + uint32_t blob[12]; + TEST_ESP_OK(nvs_set_blob(handle_3, "bl1", &blob, sizeof(blob))); + TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); + CHECK(stat1.free_entries + 4 == stat2.free_entries); + CHECK(stat1.namespace_count == 3); + CHECK(stat1.total_entries == stat2.total_entries); + CHECK(stat1.used_entries == 12); + + // amount valid pair in namespace 2 + size_t h3_count_entries; + TEST_ESP_OK(nvs_get_used_entry_count(handle_3, &h3_count_entries)); + CHECK(h3_count_entries == 4); + + CHECK(stat1.used_entries == (h1_count_entries + h2_count_entries + h3_count_entries + stat1.namespace_count)); + + nvs_close(handle_3); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +// TODO: leaks memory +TEST_CASE("Recovery from power-off when the entry being erased is not on active page", "[nvs]") +{ + const size_t blob_size = Page::CHUNK_MAX_SIZE/2 ; + size_t read_size = blob_size; + uint8_t blob[blob_size] = {0x11}; + PartitionEmulationFixture f(0, 3); + TEST_ESP_OK( NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3) ); + nvs_handle_t handle; + TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) ); + + f.emu.clearStats(); + f.emu.failAfter(Page::CHUNK_MAX_SIZE/4 + 75); + TEST_ESP_OK( nvs_set_blob(handle, "1a", blob, blob_size) ); + TEST_ESP_OK( nvs_set_blob(handle, "1b", blob, blob_size) ); + + TEST_ESP_ERR( nvs_erase_key(handle, "1a"), ESP_ERR_FLASH_OP_FAIL ); + + TEST_ESP_OK( NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3) ); + + /* Check 1a is erased fully*/ + TEST_ESP_ERR( nvs_get_blob(handle, "1a", blob, &read_size), ESP_ERR_NVS_NOT_FOUND); + + /* Check 2b is still accessible*/ + TEST_ESP_OK( nvs_get_blob(handle, "1b", blob, &read_size)); + + nvs_close(handle); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +// TODO: leaks memory +TEST_CASE("Recovery from power-off when page is being freed.", "[nvs]") +{ + const size_t blob_size = (Page::ENTRY_COUNT-3) * Page::ENTRY_SIZE; + size_t read_size = blob_size/2; + uint8_t blob[blob_size] = {0}; + PartitionEmulationFixture f(0, 3); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3)); + nvs_handle_t handle; + TEST_ESP_OK(nvs_open("test", NVS_READWRITE, &handle)); + // Fill first page + TEST_ESP_OK(nvs_set_blob(handle, "1a", blob, blob_size/3)); + TEST_ESP_OK(nvs_set_blob(handle, "1b", blob, blob_size/3)); + TEST_ESP_OK(nvs_set_blob(handle, "1c", blob, blob_size/4)); + // Fill second page + TEST_ESP_OK(nvs_set_blob(handle, "2a", blob, blob_size/2)); + TEST_ESP_OK(nvs_set_blob(handle, "2b", blob, blob_size/2)); + + TEST_ESP_OK(nvs_erase_key(handle, "1c")); + + f.emu.clearStats(); + f.emu.failAfter(6 * Page::ENTRY_COUNT); + TEST_ESP_ERR(nvs_set_blob(handle, "1d", blob, blob_size/4), ESP_ERR_FLASH_OP_FAIL); + + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3)); + + read_size = blob_size/3; + TEST_ESP_OK( nvs_get_blob(handle, "1a", blob, &read_size)); + TEST_ESP_OK( nvs_get_blob(handle, "1b", blob, &read_size)); + + read_size = blob_size /4; + TEST_ESP_ERR( nvs_get_blob(handle, "1c", blob, &read_size), ESP_ERR_NVS_NOT_FOUND); + TEST_ESP_ERR( nvs_get_blob(handle, "1d", blob, &read_size), ESP_ERR_NVS_NOT_FOUND); + + read_size = blob_size /2; + TEST_ESP_OK( nvs_get_blob(handle, "2a", blob, &read_size)); + TEST_ESP_OK( nvs_get_blob(handle, "2b", blob, &read_size)); + + TEST_ESP_OK(nvs_commit(handle)); + nvs_close(handle); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +TEST_CASE("Multi-page blobs are supported", "[nvs]") +{ + const size_t blob_size = Page::CHUNK_MAX_SIZE *2; + uint8_t blob[blob_size] = {0}; + PartitionEmulationFixture f(0, 5); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 5)); + nvs_handle_t handle; + TEST_ESP_OK(nvs_open("test", NVS_READWRITE, &handle)); + TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size)); + TEST_ESP_OK(nvs_commit(handle)); + nvs_close(handle); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +TEST_CASE("Failures are handled while storing multi-page blobs", "[nvs]") +{ + const size_t blob_size = Page::CHUNK_MAX_SIZE *7; + uint8_t blob[blob_size] = {0}; + PartitionEmulationFixture f(0, 5); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 5)); + nvs_handle_t handle; + TEST_ESP_OK(nvs_open("test", NVS_READWRITE, &handle)); + TEST_ESP_ERR(nvs_set_blob(handle, "abc", blob, blob_size), ESP_ERR_NVS_VALUE_TOO_LONG); + TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, Page::CHUNK_MAX_SIZE*2)); + TEST_ESP_OK(nvs_commit(handle)); + nvs_close(handle); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +TEST_CASE("Reading multi-page blobs", "[nvs]") +{ + const size_t blob_size = Page::CHUNK_MAX_SIZE *3; + uint8_t blob[blob_size]; + uint8_t blob_read[blob_size]; + size_t read_size = blob_size; + PartitionEmulationFixture f(0, 5); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 5)); + nvs_handle_t handle; + memset(blob, 0x11, blob_size); + memset(blob_read, 0xee, blob_size); + TEST_ESP_OK(nvs_open("readTest", NVS_READWRITE, &handle)); + TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size)); + TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size)); + CHECK(memcmp(blob, blob_read, blob_size) == 0); + TEST_ESP_OK(nvs_commit(handle)); + nvs_close(handle); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +TEST_CASE("Modification of values for Multi-page blobs are supported", "[nvs]") +{ + const size_t blob_size = Page::CHUNK_MAX_SIZE *2; + uint8_t blob[blob_size] = {0}; + uint8_t blob_read[blob_size] = {0xfe};; + uint8_t blob2[blob_size] = {0x11}; + uint8_t blob3[blob_size] = {0x22}; + uint8_t blob4[blob_size] ={ 0x33}; + size_t read_size = blob_size; + PartitionEmulationFixture f(0, 6); + TEST_ESP_OK( NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 6) ); + nvs_handle_t handle; + memset(blob, 0x11, blob_size); + memset(blob2, 0x22, blob_size); + memset(blob3, 0x33, blob_size); + memset(blob4, 0x44, blob_size); + memset(blob_read, 0xff, blob_size); + TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) ); + TEST_ESP_OK( nvs_set_blob(handle, "abc", blob, blob_size) ); + TEST_ESP_OK( nvs_set_blob(handle, "abc", blob2, blob_size) ); + TEST_ESP_OK( nvs_set_blob(handle, "abc", blob3, blob_size) ); + TEST_ESP_OK( nvs_set_blob(handle, "abc", blob4, blob_size) ); + TEST_ESP_OK( nvs_get_blob(handle, "abc", blob_read, &read_size)); + CHECK(memcmp(blob4, blob_read, blob_size) == 0); + TEST_ESP_OK( nvs_commit(handle) ); + nvs_close(handle); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +TEST_CASE("Modification from single page blob to multi-page", "[nvs]") +{ + const size_t blob_size = Page::CHUNK_MAX_SIZE *3; + uint8_t blob[blob_size] = {0}; + uint8_t blob_read[blob_size] = {0xff}; + size_t read_size = blob_size; + PartitionEmulationFixture f(0, 5); + TEST_ESP_OK( NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 5) ); + nvs_handle_t handle; + TEST_ESP_OK(nvs_open("Test", NVS_READWRITE, &handle) ); + TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, Page::CHUNK_MAX_SIZE/2)); + TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size)); + TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size)); + CHECK(memcmp(blob, blob_read, blob_size) == 0); + TEST_ESP_OK(nvs_commit(handle) ); + nvs_close(handle); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +TEST_CASE("Modification from multi-page to single page", "[nvs]") +{ + const size_t blob_size = Page::CHUNK_MAX_SIZE *3; + uint8_t blob[blob_size] = {0}; + uint8_t blob_read[blob_size] = {0xff}; + size_t read_size = blob_size; + PartitionEmulationFixture f(0, 5); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 5) ); + nvs_handle_t handle; + TEST_ESP_OK(nvs_open("Test", NVS_READWRITE, &handle) ); + TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size)); + TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, Page::CHUNK_MAX_SIZE/2)); + TEST_ESP_OK(nvs_set_blob(handle, "abc2", blob, blob_size)); + TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size)); + CHECK(memcmp(blob, blob_read, Page::CHUNK_MAX_SIZE) == 0); + TEST_ESP_OK(nvs_commit(handle) ); + nvs_close(handle); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +TEST_CASE("Multi-page blob erased using nvs_erase_key should not be found when probed for just length", "[nvs]") +{ + const size_t blob_size = Page::CHUNK_MAX_SIZE *3; + uint8_t blob[blob_size] = {0}; + size_t read_size = blob_size; + PartitionEmulationFixture f(0, 5); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 5)); + nvs_handle handle; + TEST_ESP_OK(nvs_open("Test", NVS_READWRITE, &handle)); + TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size)); + TEST_ESP_OK(nvs_erase_key(handle, "abc")); + TEST_ESP_ERR(nvs_get_blob(handle, "abc", NULL, &read_size), ESP_ERR_NVS_NOT_FOUND); + TEST_ESP_OK(nvs_commit(handle)); + nvs_close(handle); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + + +TEST_CASE("Check that orphaned blobs are erased during init", "[nvs]") +{ + const size_t blob_size = Page::CHUNK_MAX_SIZE *3 ; + uint8_t blob[blob_size] = {0x11}; + uint8_t blob2[blob_size] = {0x22}; + uint8_t blob3[blob_size] = {0x33}; + PartitionEmulationFixture f(0, 5); + Storage storage(&f.part); + + TEST_ESP_OK(storage.init(0, 5)); + + TEST_ESP_OK(storage.writeItem(1, ItemType::BLOB, "key", blob, sizeof(blob))); + + + TEST_ESP_OK(storage.init(0, 5)); + /* Check that multi-page item is still available.**/ + TEST_ESP_OK(storage.readItem(1, ItemType::BLOB, "key", blob, sizeof(blob))); + + TEST_ESP_ERR(storage.writeItem(1, ItemType::BLOB, "key2", blob, sizeof(blob)), ESP_ERR_NVS_NOT_ENOUGH_SPACE); + + Page p; + p.load(&f.part, 3); // This is where index will be placed. + p.erase(); + + TEST_ESP_OK(storage.init(0, 5)); + + TEST_ESP_ERR(storage.readItem(1, ItemType::BLOB, "key", blob, sizeof(blob)), ESP_ERR_NVS_NOT_FOUND); + TEST_ESP_OK(storage.writeItem(1, ItemType::BLOB, "key3", blob, sizeof(blob))); +} + +TEST_CASE("nvs blob fragmentation test", "[nvs]") +{ + PartitionEmulationFixture f(0, 4); + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 4) ); + const size_t BLOB_SIZE = 3500; + uint8_t *blob = (uint8_t*) malloc(BLOB_SIZE); + CHECK(blob != NULL); + memset(blob, 0xEE, BLOB_SIZE); + const uint32_t magic = 0xff33eaeb; + nvs_handle_t h; + TEST_ESP_OK( nvs_open("blob_tests", NVS_READWRITE, &h) ); + for (int i = 0; i < 128; i++) { + INFO("Iteration " << i << "...\n"); + TEST_ESP_OK( nvs_set_u32(h, "magic", magic) ); + TEST_ESP_OK( nvs_set_blob(h, "blob", blob, BLOB_SIZE) ); + char seq_buf[16]; + sprintf(seq_buf, "seq%d", i); + TEST_ESP_OK( nvs_set_u32(h, seq_buf, i) ); + } + free(blob); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +TEST_CASE("nvs code handles errors properly when partition is near to full", "[nvs]") +{ + const size_t blob_size = Page::CHUNK_MAX_SIZE * 0.3 ; + uint8_t blob[blob_size] = {0x11}; + PartitionEmulationFixture f(0, 5); + Storage storage(&f.part); + char nvs_key[16] = ""; + + TEST_ESP_OK(storage.init(0, 5)); + + /* Four pages should fit roughly 12 blobs*/ + for(uint8_t count = 1; count <= 12; count++) { + sprintf(nvs_key, "key:%u", count); + TEST_ESP_OK(storage.writeItem(1, ItemType::BLOB, nvs_key, blob, sizeof(blob))); + } + + for(uint8_t count = 13; count <= 20; count++) { + sprintf(nvs_key, "key:%u", count); + TEST_ESP_ERR(storage.writeItem(1, ItemType::BLOB, nvs_key, blob, sizeof(blob)), ESP_ERR_NVS_NOT_ENOUGH_SPACE); + } +} + +TEST_CASE("Check for nvs version incompatibility", "[nvs]") +{ + PartitionEmulationFixture f(0, 3); + + int32_t val1 = 0x12345678; + Page p; + p.load(&f.part, 0); + TEST_ESP_OK(p.setVersion(Page::NVS_VERSION - 1)); + TEST_ESP_OK(p.writeItem(1, ItemType::I32, "foo", &val1, sizeof(val1))); + + TEST_ESP_ERR(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3), + ESP_ERR_NVS_NEW_VERSION_FOUND); + + // if something went wrong, clean up + nvs_flash_deinit_partition(f.part.get_partition_name()); +} + +TEST_CASE("Check that NVS supports old blob format without blob index", "[nvs]") +{ + SpiFlashEmulator emu("../nvs_partition_generator/part_old_blob_format.bin"); + PartitionEmulation part(&emu, 0, 2 * SPI_FLASH_SEC_SIZE, "test"); + nvs_handle_t handle; + + TEST_ESP_OK( NVSPartitionManager::get_instance()->init_custom(&part, 0, 2) ); + TEST_ESP_OK( nvs_open_from_partition("test", "dummyNamespace", NVS_READWRITE, &handle)); + + char buf[64] = {0}; + size_t buflen = 64; + uint8_t hexdata[] = {0x01, 0x02, 0x03, 0xab, 0xcd, 0xef}; + TEST_ESP_OK( nvs_get_blob(handle, "dummyHex2BinKey", buf, &buflen)); + CHECK(memcmp(buf, hexdata, buflen) == 0); + + buflen = 64; + uint8_t base64data[] = {'1', '2', '3', 'a', 'b', 'c'}; + TEST_ESP_OK( nvs_get_blob(handle, "dummyBase64Key", buf, &buflen)); + CHECK(memcmp(buf, base64data, buflen) == 0); + + Page p; + p.load(&part, 0); + + /* Check that item is stored in old format without blob index*/ + TEST_ESP_OK(p.findItem(1, ItemType::BLOB, "dummyHex2BinKey")); + + /* Modify the blob so that it is stored in the new format*/ + hexdata[0] = hexdata[1] = hexdata[2] = 0x99; + TEST_ESP_OK(nvs_set_blob(handle, "dummyHex2BinKey", hexdata, sizeof(hexdata))); + + Page p2; + p2.load(&part, 0); + + /* Check the type of the blob. Expect type mismatch since the blob is stored in new format*/ + TEST_ESP_ERR(p2.findItem(1, ItemType::BLOB, "dummyHex2BinKey"), ESP_ERR_NVS_TYPE_MISMATCH); + + /* Check that index is present for the modified blob according to new format*/ + TEST_ESP_OK(p2.findItem(1, ItemType::BLOB_IDX, "dummyHex2BinKey")); + + /* Read the blob in new format and check the contents*/ + buflen = 64; + TEST_ESP_OK( nvs_get_blob(handle, "dummyBase64Key", buf, &buflen)); + CHECK(memcmp(buf, base64data, buflen) == 0); + + TEST_ESP_OK(nvs_flash_deinit_partition(part.get_partition_name())); +} + +// TODO: leaks memory +TEST_CASE("monkey test with old-format blob present", "[nvs][monkey]") +{ + std::random_device rd; + std::mt19937 gen(rd()); + uint32_t seed = 3; + gen.seed(seed); + + PartitionEmulationFixture f(0, 10); + f.emu.randomize(seed); + f.emu.clearStats(); + + const uint32_t NVS_FLASH_SECTOR = 2; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 8; + static const size_t smallBlobLen = Page::CHUNK_MAX_SIZE / 3; + + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + + nvs_handle_t handle; + TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); + RandomTest test; + + for ( uint8_t it = 0; it < 10; it++) { + size_t count = 200; + + /* Erase index and chunks for the blob with "singlepage" key */ + for (uint8_t num = NVS_FLASH_SECTOR; num < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; num++) { + Page p; + p.load(&f.part, num); + p.eraseItem(1, ItemType::BLOB, "singlepage", Item::CHUNK_ANY, VerOffset::VER_ANY); + p.eraseItem(1, ItemType::BLOB_IDX, "singlepage", Item::CHUNK_ANY, VerOffset::VER_ANY); + p.eraseItem(1, ItemType::BLOB_DATA, "singlepage", Item::CHUNK_ANY, VerOffset::VER_ANY); + } + + /* Now write "singlepage" blob in old format*/ + for (uint8_t num = NVS_FLASH_SECTOR; num < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; num++) { + Page p; + p.load(&f.part, num); + if (p.state() == Page::PageState::ACTIVE) { + uint8_t buf[smallBlobLen]; + size_t blobLen = gen() % smallBlobLen; + + if(blobLen > p.getVarDataTailroom()) { + blobLen = p.getVarDataTailroom(); + } + + std::generate_n(buf, blobLen, [&]() -> uint8_t { + return static_cast(gen() % 256); + }); + + TEST_ESP_OK(p.writeItem(1, ItemType::BLOB, "singlepage", buf, blobLen, Item::CHUNK_ANY)); + TEST_ESP_OK(p.findItem(1, ItemType::BLOB, "singlepage")); + test.handleExternalWriteAtIndex(9, buf, blobLen); // This assumes "singlepage" is always at index 9 + + break; + } + } + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); + /* Initialize again */ + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, + NVS_FLASH_SECTOR, + NVS_FLASH_SECTOR_COUNT_MIN)); + TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); + + /* Perform random things */ + auto res = test.doRandomThings(handle, gen, count); + if (res != ESP_OK) { + nvs_dump(NVS_DEFAULT_PART_NAME); + CHECK(0); + } + + /* Check that only one version is present for "singlepage". Its possible that last iteration did not write + * anything for "singlepage". So either old version or new version should be present.*/ + bool oldVerPresent = false, newVerPresent = false; + + for (uint8_t num = NVS_FLASH_SECTOR; num < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; num++) { + Page p; + p.load(&f.part, num); + if(!oldVerPresent && p.findItem(1, ItemType::BLOB, "singlepage", Item::CHUNK_ANY, VerOffset::VER_ANY) == ESP_OK) { + oldVerPresent = true; + } + + if(!newVerPresent && p.findItem(1, ItemType::BLOB_IDX, "singlepage", Item::CHUNK_ANY, VerOffset::VER_ANY) == ESP_OK) { + newVerPresent = true; + } + } + CHECK(oldVerPresent != newVerPresent); + } + + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); + s_perf << "Monkey test: nErase=" << f.emu.getEraseOps() << " nWrite=" << f.emu.getWriteOps() << std::endl; +} + +TEST_CASE("Recovery from power-off during modification of blob present in old-format (same page)", "[nvs]") +{ + std::random_device rd; + std::mt19937 gen(rd()); + uint32_t seed = 3; + gen.seed(seed); + + PartitionEmulationFixture f(0, 3); + f.emu.clearStats(); + + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3)); + + nvs_handle_t handle; + TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); + + uint8_t hexdata[] = {0x01, 0x02, 0x03, 0xab, 0xcd, 0xef}; + uint8_t hexdata_old[] = {0x11, 0x12, 0x13, 0xbb, 0xcc, 0xee}; + size_t buflen = sizeof(hexdata); + uint8_t buf[Page::CHUNK_MAX_SIZE]; + + /* Power-off when blob was being written on the same page where its old version in old format + * was present*/ + Page p; + p.load(&f.part, 0); + /* Write blob in old-format*/ + TEST_ESP_OK(p.writeItem(1, ItemType::BLOB, "singlepage", hexdata_old, sizeof(hexdata_old))); + + /* Write blob in new format*/ + TEST_ESP_OK(p.writeItem(1, ItemType::BLOB_DATA, "singlepage", hexdata, sizeof(hexdata), 0)); + /* All pages are stored. Now store the index.*/ + Item item; + item.blobIndex.dataSize = sizeof(hexdata); + item.blobIndex.chunkCount = 1; + item.blobIndex.chunkStart = VerOffset::VER_0_OFFSET; + + TEST_ESP_OK(p.writeItem(1, ItemType::BLOB_IDX, "singlepage", item.data, sizeof(item.data))); + + TEST_ESP_OK(p.findItem(1, ItemType::BLOB, "singlepage")); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); + /* Initialize again */ + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3)); + TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); + + TEST_ESP_OK( nvs_get_blob(handle, "singlepage", buf, &buflen)); + CHECK(memcmp(buf, hexdata, buflen) == 0); + + Page p2; + p2.load(&f.part, 0); + TEST_ESP_ERR(p2.findItem(1, ItemType::BLOB, "singlepage"), ESP_ERR_NVS_TYPE_MISMATCH); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +TEST_CASE("Recovery from power-off during modification of blob present in old-format (different page)", "[nvs]") +{ + std::random_device rd; + std::mt19937 gen(rd()); + uint32_t seed = 3; + gen.seed(seed); + + PartitionEmulationFixture f(0, 3); + f.emu.clearStats(); + + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3)); + + nvs_handle_t handle; + TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); + + uint8_t hexdata[] = {0x01, 0x02, 0x03, 0xab, 0xcd, 0xef}; + uint8_t hexdata_old[] = {0x11, 0x12, 0x13, 0xbb, 0xcc, 0xee}; + size_t buflen = sizeof(hexdata); + uint8_t buf[Page::CHUNK_MAX_SIZE]; + + + /* Power-off when blob was being written on the different page where its old version in old format + * was present*/ + Page p; + p.load(&f.part, 0); + /* Write blob in old-format*/ + TEST_ESP_OK(p.writeItem(1, ItemType::BLOB, "singlepage", hexdata_old, sizeof(hexdata_old))); + + /* Write blob in new format*/ + TEST_ESP_OK(p.writeItem(1, ItemType::BLOB_DATA, "singlepage", hexdata, sizeof(hexdata), 0)); + /* All pages are stored. Now store the index.*/ + Item item; + item.blobIndex.dataSize = sizeof(hexdata); + item.blobIndex.chunkCount = 1; + item.blobIndex.chunkStart = VerOffset::VER_0_OFFSET; + p.markFull(); + Page p2; + p2.load(&f.part, 1); + p2.setSeqNumber(1); + + TEST_ESP_OK(p2.writeItem(1, ItemType::BLOB_IDX, "singlepage", item.data, sizeof(item.data))); + + TEST_ESP_OK(p.findItem(1, ItemType::BLOB, "singlepage")); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); + /* Initialize again */ + TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(&f.part, 0, 3)); + TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); + + TEST_ESP_OK( nvs_get_blob(handle, "singlepage", buf, &buflen)); + CHECK(memcmp(buf, hexdata, buflen) == 0); + + Page p3; + p3.load(&f.part, 0); + TEST_ESP_ERR(p3.findItem(1, ItemType::BLOB, "singlepage"), ESP_ERR_NVS_NOT_FOUND); + + TEST_ESP_OK(nvs_flash_deinit_partition(f.part.get_partition_name())); +} + +static void check_nvs_part_gen_args(SpiFlashEmulator *spi_flash_emulator, + char const *part_name, + int size, + char const *filename, + bool is_encr, + nvs_sec_cfg_t* xts_cfg) +{ + nvs_handle_t handle; + + esp_partition_t esp_part; + esp_part.encrypted = false; // we're not testing generic flash encryption here, only the legacy NVS encryption + esp_part.address = 0; + esp_part.size = size * SPI_FLASH_SEC_SIZE; + strncpy(esp_part.label, part_name, PART_NAME_MAX_SIZE); + shared_ptr part; + + if (is_encr) { + NVSEncryptedPartition *enc_part = new NVSEncryptedPartition(&esp_part); + TEST_ESP_OK(enc_part->init(xts_cfg)); + part.reset(enc_part); + } else { + part.reset(new PartitionEmulation(spi_flash_emulator, 0, size, part_name)); + } + + TEST_ESP_OK( NVSPartitionManager::get_instance()->init_custom(part.get(), 0, size) ); + + TEST_ESP_OK( nvs_open_from_partition(part_name, "dummyNamespace", NVS_READONLY, &handle)); + uint8_t u8v; + TEST_ESP_OK( nvs_get_u8(handle, "dummyU8Key", &u8v)); + CHECK(u8v == 127); + int8_t i8v; + TEST_ESP_OK( nvs_get_i8(handle, "dummyI8Key", &i8v)); + CHECK(i8v == -128); + uint16_t u16v; + TEST_ESP_OK( nvs_get_u16(handle, "dummyU16Key", &u16v)); + CHECK(u16v == 32768); + uint32_t u32v; + TEST_ESP_OK( nvs_get_u32(handle, "dummyU32Key", &u32v)); + CHECK(u32v == 4294967295); + int32_t i32v; + TEST_ESP_OK( nvs_get_i32(handle, "dummyI32Key", &i32v)); + CHECK(i32v == -2147483648); + + char buf[64] = {0}; + size_t buflen = 64; + TEST_ESP_OK( nvs_get_str(handle, "dummyStringKey", buf, &buflen)); + CHECK(strncmp(buf, "0A:0B:0C:0D:0E:0F", buflen) == 0); + + uint8_t hexdata[] = {0x01, 0x02, 0x03, 0xab, 0xcd, 0xef}; + buflen = 64; + int j; + TEST_ESP_OK( nvs_get_blob(handle, "dummyHex2BinKey", buf, &buflen)); + CHECK(memcmp(buf, hexdata, buflen) == 0); + + uint8_t base64data[] = {'1', '2', '3', 'a', 'b', 'c'}; + TEST_ESP_OK( nvs_get_blob(handle, "dummyBase64Key", buf, &buflen)); + CHECK(memcmp(buf, base64data, buflen) == 0); + + buflen = 64; + uint8_t hexfiledata[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}; + TEST_ESP_OK( nvs_get_blob(handle, "hexFileKey", buf, &buflen)); + CHECK(memcmp(buf, hexfiledata, buflen) == 0); + + buflen = 64; + uint8_t strfiledata[64] = "abcdefghijklmnopqrstuvwxyz\0"; + TEST_ESP_OK( nvs_get_str(handle, "stringFileKey", buf, &buflen)); + CHECK(memcmp(buf, strfiledata, buflen) == 0); + + char bin_data[5200]; + size_t bin_len = sizeof(bin_data); + char binfiledata[5200]; + ifstream file; + file.open(filename); + file.read(binfiledata,5200); + TEST_ESP_OK( nvs_get_blob(handle, "binFileKey", bin_data, &bin_len)); + CHECK(memcmp(bin_data, binfiledata, bin_len) == 0); + + file.close(); + + nvs_close(handle); + + TEST_ESP_OK(nvs_flash_deinit_partition(part_name)); +} + + +TEST_CASE("check and read data from partition generated via partition generation utility with multipage blob support disabled", "[nvs_part_gen]") +{ + int status; + int childpid = fork(); + if (childpid == 0) { + exit(execlp("cp", " cp", + "-rf", + "../nvs_partition_generator/testdata", + ".",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) != -1); + + childpid = fork(); + + if (childpid == 0) { + exit(execlp("python", "python", + "../nvs_partition_generator/nvs_partition_gen.py", + "generate", + "../nvs_partition_generator/sample_singlepage_blob.csv", + "partition_single_page.bin", + "0x3000", + "--version", + "1", + "--outdir", + "../nvs_partition_generator",NULL)); + } else { + CHECK(childpid > 0); + int status; + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + } + } + + SpiFlashEmulator emu("../nvs_partition_generator/partition_single_page.bin"); + + check_nvs_part_gen_args(&emu, "test", 3, "../nvs_partition_generator/testdata/sample_singlepage_blob.bin", false, NULL); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("rm", " rm", + "-rf", + "testdata",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } +} + +TEST_CASE("check and read data from partition generated via partition generation utility with multipage blob support enabled", "[nvs_part_gen]") +{ + int status; + int childpid = fork(); + if (childpid == 0) { + exit(execlp("cp", " cp", + "-rf", + "../nvs_partition_generator/testdata", + ".",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + + if (childpid == 0) { + exit(execlp("python", "python", + "../nvs_partition_generator/nvs_partition_gen.py", + "generate", + "../nvs_partition_generator/sample_multipage_blob.csv", + "partition_multipage_blob.bin", + "0x4000", + "--version", + "2", + "--outdir", + "../nvs_partition_generator",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + } + } + + SpiFlashEmulator emu("../nvs_partition_generator/partition_multipage_blob.bin"); + + check_nvs_part_gen_args(&emu, "test", 4, "../nvs_partition_generator/testdata/sample_multipage_blob.bin",false,NULL); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("rm", " rm", + "-rf", + "testdata",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } +} + +TEST_CASE("check and read data from partition generated via manufacturing utility with multipage blob support disabled", "[mfg_gen]") +{ + int childpid = fork(); + int status; + + if (childpid == 0) { + exit(execlp("bash", "bash", + "-c", + "rm -rf ../../../tools/mass_mfg/host_test && \ + cp -rf ../../../tools/mass_mfg/testdata mfg_testdata && \ + cp -rf ../nvs_partition_generator/testdata . && \ + mkdir -p ../../../tools/mass_mfg/host_test", NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("python", "python", + "../../../tools/mass_mfg/mfg_gen.py", + "generate", + "../../../tools/mass_mfg/samples/sample_config.csv", + "../../../tools/mass_mfg/samples/sample_values_singlepage_blob.csv", + "Test", + "0x3000", + "--outdir", + "../../../tools/mass_mfg/host_test", + "--version", + "1",NULL)); + + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("python", "python", + "../nvs_partition_generator/nvs_partition_gen.py", + "generate", + "../../../tools/mass_mfg/host_test/csv/Test-1.csv", + "../nvs_partition_generator/Test-1-partition.bin", + "0x3000", + "--version", + "1",NULL)); + + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } + + } + + } + + SpiFlashEmulator emu1("../../../tools/mass_mfg/host_test/bin/Test-1.bin"); + check_nvs_part_gen_args(&emu1, "test", 3, "mfg_testdata/sample_singlepage_blob.bin", false, NULL); + + SpiFlashEmulator emu2("../nvs_partition_generator/Test-1-partition.bin"); + check_nvs_part_gen_args(&emu2, "test", 3, "testdata/sample_singlepage_blob.bin", false, NULL); + + + childpid = fork(); + if (childpid == 0) { + exit(execlp("bash", " bash", + "-c", + "rm -rf ../../../tools/mass_mfg/host_test | \ + rm -rf mfg_testdata | \ + rm -rf testdata",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } + +} + +TEST_CASE("check and read data from partition generated via manufacturing utility with multipage blob support enabled", "[mfg_gen]") +{ + int childpid = fork(); + int status; + + if (childpid == 0) { + exit(execlp("bash", " bash", + "-c", + "rm -rf ../../../tools/mass_mfg/host_test | \ + cp -rf ../../../tools/mass_mfg/testdata mfg_testdata | \ + cp -rf ../nvs_partition_generator/testdata . | \ + mkdir -p ../../../tools/mass_mfg/host_test",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("python", "python", + "../../../tools/mass_mfg/mfg_gen.py", + "generate", + "../../../tools/mass_mfg/samples/sample_config.csv", + "../../../tools/mass_mfg/samples/sample_values_multipage_blob.csv", + "Test", + "0x4000", + "--outdir", + "../../../tools/mass_mfg/host_test", + "--version", + "2",NULL)); + + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("python", "python", + "../nvs_partition_generator/nvs_partition_gen.py", + "generate", + "../../../tools/mass_mfg/host_test/csv/Test-1.csv", + "../nvs_partition_generator/Test-1-partition.bin", + "0x4000", + "--version", + "2",NULL)); + + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } + + } + + } + + SpiFlashEmulator emu1("../../../tools/mass_mfg/host_test/bin/Test-1.bin"); + check_nvs_part_gen_args(&emu1, "test", 4, "mfg_testdata/sample_multipage_blob.bin", false, NULL); + + SpiFlashEmulator emu2("../nvs_partition_generator/Test-1-partition.bin"); + check_nvs_part_gen_args(&emu2, "test", 4, "testdata/sample_multipage_blob.bin", false, NULL); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("bash", " bash", + "-c", + "rm -rf ../../../tools/mass_mfg/host_test | \ + rm -rf mfg_testdata | \ + rm -rf testdata",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } + +} + +#if CONFIG_NVS_ENCRYPTION +TEST_CASE("check underlying xts code for 32-byte size sector encryption", "[nvs]") +{ + auto toHex = [](char ch) { + if(ch >= '0' && ch <= '9') + return ch - '0'; + else if(ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if(ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else + return 0; + }; + + auto toHexByte = [toHex](char* c) { + return 16 * toHex(c[0]) + toHex(c[1]); + }; + + auto toHexStream = [toHexByte](char* src, uint8_t* dest) { + uint32_t cnt =0; + char* p = src; + while(*p != '\0' && *(p + 1) != '\0') + { + dest[cnt++] = toHexByte(p); p += 2; + } + }; + + uint8_t eky_hex[2 * NVS_KEY_SIZE]; + uint8_t ptxt_hex[Page::ENTRY_SIZE], ctxt_hex[Page::ENTRY_SIZE], ba_hex[16]; + mbedtls_aes_xts_context ectx[1]; + mbedtls_aes_xts_context dctx[1]; + + char eky[][2 * NVS_KEY_SIZE + 1] = { + "0000000000000000000000000000000000000000000000000000000000000000", + "1111111111111111111111111111111111111111111111111111111111111111" + }; + char tky[][2 * NVS_KEY_SIZE + 1] = { + "0000000000000000000000000000000000000000000000000000000000000000", + "2222222222222222222222222222222222222222222222222222222222222222" + }; + char blk_addr[][2*16 + 1] = { + "00000000000000000000000000000000", + "33333333330000000000000000000000" + }; + + char ptxt[][2 * Page::ENTRY_SIZE + 1] = { + "0000000000000000000000000000000000000000000000000000000000000000", + "4444444444444444444444444444444444444444444444444444444444444444" + }; + char ctxt[][2 * Page::ENTRY_SIZE + 1] = { + "d456b4fc2e620bba6ffbed27b956c9543454dd49ebd8d8ee6f94b65cbe158f73", + "e622334f184bbce129a25b2ac76b3d92abf98e22df5bdd15af471f3db8946a85" + }; + + mbedtls_aes_xts_init(ectx); + mbedtls_aes_xts_init(dctx); + + for(uint8_t cnt = 0; cnt < sizeof(eky)/sizeof(eky[0]); cnt++) { + toHexStream(eky[cnt], eky_hex); + toHexStream(tky[cnt], &eky_hex[NVS_KEY_SIZE]); + toHexStream(ptxt[cnt], ptxt_hex); + toHexStream(ctxt[cnt], ctxt_hex); + toHexStream(blk_addr[cnt], ba_hex); + + CHECK(!mbedtls_aes_xts_setkey_enc(ectx, eky_hex, 2 * NVS_KEY_SIZE * 8)); + CHECK(!mbedtls_aes_xts_setkey_enc(dctx, eky_hex, 2 * NVS_KEY_SIZE * 8)); + + CHECK(!mbedtls_aes_crypt_xts(ectx, MBEDTLS_AES_ENCRYPT, Page::ENTRY_SIZE, ba_hex, ptxt_hex, ptxt_hex)); + + CHECK(!memcmp(ptxt_hex, ctxt_hex, Page::ENTRY_SIZE)); + } +} + +TEST_CASE("test nvs apis with encryption enabled", "[nvs]") +{ + nvs_handle_t handle_1; + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + + nvs_sec_cfg_t xts_cfg; + for(int count = 0; count < NVS_KEY_SIZE; count++) { + xts_cfg.eky[count] = 0x11; + xts_cfg.tky[count] = 0x22; + } + EncryptedPartitionFixture fixture(&xts_cfg, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN); + fixture.emu.randomize(100); + fixture.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + for (uint16_t i = NVS_FLASH_SECTOR; i + init_custom(&fixture.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); + + TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND); + + TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1)); + TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678)); + TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789)); + + nvs_handle_t handle_2; + TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2)); + TEST_ESP_OK(nvs_set_i32(handle_2, "foo", 0x3456789a)); + const char* str = "value 0123456789abcdef0123456789abcdef"; + TEST_ESP_OK(nvs_set_str(handle_2, "key", str)); + + int32_t v1; + TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1)); + CHECK(0x23456789 == v1); + + int32_t v2; + TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2)); + CHECK(0x3456789a == v2); + + char buf[strlen(str) + 1]; + size_t buf_len = sizeof(buf); + + size_t buf_len_needed; + TEST_ESP_OK(nvs_get_str(handle_2, "key", NULL, &buf_len_needed)); + CHECK(buf_len_needed == buf_len); + + size_t buf_len_short = buf_len - 1; + TEST_ESP_ERR(ESP_ERR_NVS_INVALID_LENGTH, nvs_get_str(handle_2, "key", buf, &buf_len_short)); + CHECK(buf_len_short == buf_len); + + size_t buf_len_long = buf_len + 1; + TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len_long)); + CHECK(buf_len_long == buf_len); + + TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len)); + + CHECK(0 == strcmp(buf, str)); + nvs_close(handle_1); + nvs_close(handle_2); + TEST_ESP_OK(nvs_flash_deinit()); + +} + +TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled", "[nvs_part_gen]") +{ + int status; + int childpid = fork(); + if (childpid == 0) { + exit(execlp("cp", " cp", + "-rf", + "../nvs_partition_generator/testdata", + ".",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + + if (childpid == 0) { + exit(execlp("python", "python", + "../nvs_partition_generator/nvs_partition_gen.py", + "encrypt", + "../nvs_partition_generator/sample_multipage_blob.csv", + "partition_encrypted.bin", + "0x4000", + "--inputkey", + "../nvs_partition_generator/testdata/sample_encryption_keys.bin", + "--outdir", + "../nvs_partition_generator",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + } + } + + SpiFlashEmulator emu("../nvs_partition_generator/partition_encrypted.bin"); + + nvs_sec_cfg_t cfg; + for(int count = 0; count < NVS_KEY_SIZE; count++) { + cfg.eky[count] = 0x11; + cfg.tky[count] = 0x22; + } + + check_nvs_part_gen_args(&emu, NVS_DEFAULT_PART_NAME, 4, "../nvs_partition_generator/testdata/sample_multipage_blob.bin", true, &cfg); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("rm", " rm", + "-rf", + "testdata",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } + +} + +TEST_CASE("test decrypt functionality for encrypted data", "[nvs_part_gen]") +{ + + //retrieving the temporary test data + int status = system("cp -rf ../nvs_partition_generator/testdata ."); + CHECK(status == 0); + + //encoding data from sample_multipage_blob.csv + status = system("python ../nvs_partition_generator/nvs_partition_gen.py generate ../nvs_partition_generator/sample_multipage_blob.csv partition_encoded.bin 0x5000 --outdir ../nvs_partition_generator"); + CHECK(status == 0); + + //encrypting data from sample_multipage_blob.csv + status = system("python ../nvs_partition_generator/nvs_partition_gen.py encrypt ../nvs_partition_generator/sample_multipage_blob.csv partition_encrypted.bin 0x5000 --inputkey ../nvs_partition_generator/testdata/sample_encryption_keys.bin --outdir ../nvs_partition_generator"); + CHECK(status == 0); + + //decrypting data from partition_encrypted.bin + status = system("python ../nvs_partition_generator/nvs_partition_gen.py decrypt ../nvs_partition_generator/partition_encrypted.bin ../nvs_partition_generator/testdata/sample_encryption_keys.bin ../nvs_partition_generator/partition_decrypted.bin"); + CHECK(status == 0); + + status = system("diff ../nvs_partition_generator/partition_decrypted.bin ../nvs_partition_generator/partition_encoded.bin"); + CHECK(status == 0); + CHECK(WEXITSTATUS(status) == 0); + + + //cleaning up the temporary test data + status = system("rm -rf testdata"); + CHECK(status == 0); + +} + +TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled using keygen", "[nvs_part_gen]") +{ + int childpid = fork(); + int status; + + if (childpid == 0) { + exit(execlp("cp", " cp", + "-rf", + "../nvs_partition_generator/testdata", + ".",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + + if (childpid == 0) { + exit(execlp("rm", " rm", + "-rf", + "../nvs_partition_generator/keys",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("python", "python", + "../nvs_partition_generator/nvs_partition_gen.py", + "encrypt", + "../nvs_partition_generator/sample_multipage_blob.csv", + "partition_encrypted_using_keygen.bin", + "0x4000", + "--keygen", + "--outdir", + "../nvs_partition_generator",NULL)); + + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } + } + } + + + DIR *dir; + struct dirent *file; + char *filename; + char *files; + char *file_ext; + + dir = opendir("../nvs_partition_generator/keys"); + while ((file = readdir(dir)) != NULL) + { + filename = file->d_name; + files = strrchr(filename, '.'); + if (files != NULL) + { + file_ext = files+1; + if (strncmp(file_ext,"bin",3) == 0) + { + break; + } + } + } + + std::string encr_file = std::string("../nvs_partition_generator/keys/") + std::string(filename); + SpiFlashEmulator emu("../nvs_partition_generator/partition_encrypted_using_keygen.bin"); + + char buffer[64]; + FILE *fp; + + fp = fopen(encr_file.c_str(),"rb"); + fread(buffer,sizeof(buffer),1,fp); + + fclose(fp); + + nvs_sec_cfg_t cfg; + + for(int count = 0; count < NVS_KEY_SIZE; count++) { + cfg.eky[count] = buffer[count] & 255; + cfg.tky[count] = buffer[count+32] & 255; + } + + check_nvs_part_gen_args(&emu, NVS_DEFAULT_PART_NAME, 4, "../nvs_partition_generator/testdata/sample_multipage_blob.bin", true, &cfg); + } +TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled using inputkey", "[nvs_part_gen]") +{ + int childpid = fork(); + int status; + + DIR *dir; + struct dirent *file; + char *filename; + char *files; + char *file_ext; + + dir = opendir("../nvs_partition_generator/keys"); + while ((file = readdir(dir)) != NULL) + { + filename = file->d_name; + files = strrchr(filename, '.'); + if (files != NULL) + { + file_ext = files+1; + if (strncmp(file_ext,"bin",3) == 0) + { + break; + } + } + } + + std::string encr_file = std::string("../nvs_partition_generator/keys/") + std::string(filename); + + if (childpid == 0) { + exit(execlp("python", "python", + "../nvs_partition_generator/nvs_partition_gen.py", + "encrypt", + "../nvs_partition_generator/sample_multipage_blob.csv", + "partition_encrypted_using_keyfile.bin", + "0x4000", + "--inputkey", + encr_file.c_str(), + "--outdir", + "../nvs_partition_generator",NULL)); + + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + } + + SpiFlashEmulator emu("../nvs_partition_generator/partition_encrypted_using_keyfile.bin"); + + char buffer[64]; + FILE *fp; + + fp = fopen(encr_file.c_str(),"rb"); + fread(buffer,sizeof(buffer),1,fp); + + fclose(fp); + + nvs_sec_cfg_t cfg; + + for(int count = 0; count < NVS_KEY_SIZE; count++) { + cfg.eky[count] = buffer[count] & 255; + cfg.tky[count] = buffer[count+32] & 255; + } + + check_nvs_part_gen_args(&emu, NVS_DEFAULT_PART_NAME, 4, "../nvs_partition_generator/testdata/sample_multipage_blob.bin", true, &cfg); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("rm", " rm", + "-rf", + "../nvs_partition_generator/keys",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + + if (childpid == 0) { + exit(execlp("rm", " rm", + "-rf", + "testdata",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + } + } + +} + +TEST_CASE("check and read data from partition generated via manufacturing utility with encryption enabled using sample inputkey", "[mfg_gen]") +{ + int childpid = fork(); + int status; + + if (childpid == 0) { + exit(execlp("bash", " bash", + "-c", + "rm -rf ../../../tools/mass_mfg/host_test | \ + cp -rf ../../../tools/mass_mfg/testdata mfg_testdata | \ + cp -rf ../nvs_partition_generator/testdata . | \ + mkdir -p ../../../tools/mass_mfg/host_test",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("python", "python", + "../../../tools/mass_mfg/mfg_gen.py", + "generate", + "../../../tools/mass_mfg/samples/sample_config.csv", + "../../../tools/mass_mfg/samples/sample_values_multipage_blob.csv", + "Test", + "0x4000", + "--outdir", + "../../../tools/mass_mfg/host_test", + "--version", + "2", + "--inputkey", + "mfg_testdata/sample_encryption_keys.bin",NULL)); + + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("python", "python", + "../nvs_partition_generator/nvs_partition_gen.py", + "encrypt", + "../../../tools/mass_mfg/host_test/csv/Test-1.csv", + "../nvs_partition_generator/Test-1-partition-encrypted.bin", + "0x4000", + "--version", + "2", + "--inputkey", + "testdata/sample_encryption_keys.bin",NULL)); + + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } + + } + + } + + SpiFlashEmulator emu1("../../../tools/mass_mfg/host_test/bin/Test-1.bin"); + + nvs_sec_cfg_t cfg; + for(int count = 0; count < NVS_KEY_SIZE; count++) { + cfg.eky[count] = 0x11; + cfg.tky[count] = 0x22; + } + + check_nvs_part_gen_args(&emu1, NVS_DEFAULT_PART_NAME, 4, "mfg_testdata/sample_multipage_blob.bin", true, &cfg); + + SpiFlashEmulator emu2("../nvs_partition_generator/Test-1-partition-encrypted.bin"); + + check_nvs_part_gen_args(&emu2, NVS_DEFAULT_PART_NAME, 4, "testdata/sample_multipage_blob.bin", true, &cfg); + + + childpid = fork(); + if (childpid == 0) { + exit(execlp("bash", " bash", + "-c", + "rm -rf ../../../tools/mass_mfg/host_test | \ + rm -rf mfg_testdata | \ + rm -rf testdata",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } + +} + +TEST_CASE("check and read data from partition generated via manufacturing utility with encryption enabled using new generated key", "[mfg_gen]") +{ + int childpid = fork(); + int status; + + if (childpid == 0) { + exit(execlp("bash", " bash", + "-c", + "rm -rf ../../../tools/mass_mfg/host_test | \ + cp -rf ../../../tools/mass_mfg/testdata mfg_testdata | \ + cp -rf ../nvs_partition_generator/testdata . | \ + mkdir -p ../../../tools/mass_mfg/host_test",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("python", "python", + "../../../tools/mass_mfg/mfg_gen.py", + "generate-key", + "--outdir", + "../../../tools/mass_mfg/host_test", + "--keyfile", + "encr_keys_host_test.bin",NULL)); + + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("python", "python", + "../../../tools/mass_mfg/mfg_gen.py", + "generate", + "../../../tools/mass_mfg/samples/sample_config.csv", + "../../../tools/mass_mfg/samples/sample_values_multipage_blob.csv", + "Test", + "0x4000", + "--outdir", + "../../../tools/mass_mfg/host_test", + "--version", + "2", + "--inputkey", + "../../../tools/mass_mfg/host_test/keys/encr_keys_host_test.bin",NULL)); + + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("python", "python", + "../nvs_partition_generator/nvs_partition_gen.py", + "encrypt", + "../../../tools/mass_mfg/host_test/csv/Test-1.csv", + "../nvs_partition_generator/Test-1-partition-encrypted.bin", + "0x4000", + "--version", + "2", + "--inputkey", + "../../../tools/mass_mfg/host_test/keys/encr_keys_host_test.bin",NULL)); + + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } + + } + + } + + } + + + SpiFlashEmulator emu1("../../../tools/mass_mfg/host_test/bin/Test-1.bin"); + + char buffer[64]; + FILE *fp; + + fp = fopen("../../../tools/mass_mfg/host_test/keys/encr_keys_host_test.bin","rb"); + fread(buffer,sizeof(buffer),1,fp); + + fclose(fp); + + nvs_sec_cfg_t cfg; + + for(int count = 0; count < NVS_KEY_SIZE; count++) { + cfg.eky[count] = buffer[count] & 255; + cfg.tky[count] = buffer[count+32] & 255; + } + + check_nvs_part_gen_args(&emu1, NVS_DEFAULT_PART_NAME, 4, "mfg_testdata/sample_multipage_blob.bin", true, &cfg); + + SpiFlashEmulator emu2("../nvs_partition_generator/Test-1-partition-encrypted.bin"); + + check_nvs_part_gen_args(&emu2, NVS_DEFAULT_PART_NAME, 4, "testdata/sample_multipage_blob.bin", true, &cfg); + + childpid = fork(); + if (childpid == 0) { + exit(execlp("bash", " bash", + "-c", + "rm -rf keys | \ + rm -rf mfg_testdata | \ + rm -rf testdata | \ + rm -rf ../../../tools/mass_mfg/host_test",NULL)); + } else { + CHECK(childpid > 0); + waitpid(childpid, &status, 0); + CHECK(WEXITSTATUS(status) == 0); + + } + +} +#endif + +/* Add new tests above */ +/* This test has to be the final one */ + TEST_CASE("dump all performance data", "[nvs]") { std::cout << "====================" << std::endl << "Dumping benchmarks" << std::endl; diff --git a/components/nvs_flash/test_nvs_host/test_nvs_cxx_api.cpp b/components/nvs_flash/test_nvs_host/test_nvs_cxx_api.cpp new file mode 100644 index 000000000..da1d006be --- /dev/null +++ b/components/nvs_flash/test_nvs_host/test_nvs_cxx_api.cpp @@ -0,0 +1,193 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "catch.hpp" +#include +#include +#include "nvs_test_api.h" +#include "nvs_handle_simple.hpp" +#include "nvs_partition_manager.hpp" +#include "spi_flash_emulation.h" + +#include "test_fixtures.hpp" + +#include + +using namespace std; + +TEST_CASE("NVSHandleSimple CXX api open invalid arguments", "[nvs cxx]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10, "test"); + esp_err_t result; + shared_ptr handle; + + REQUIRE(nvs::NVSPartitionManager::get_instance()-> + init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK); + + handle = nvs::open_nvs_handle_from_partition(nullptr, "ns_1", NVS_READWRITE, &result); + CHECK(result == ESP_ERR_INVALID_ARG); + CHECK(!handle); + + handle = nvs::open_nvs_handle_from_partition("test", nullptr, NVS_READWRITE, &result); + CHECK(result == ESP_ERR_INVALID_ARG); + CHECK(!handle); + + nvs::NVSPartitionManager::get_instance()->deinit_partition("test"); +} + +TEST_CASE("NVSHandleSimple CXX api open partition uninitialized", "[nvs cxx]") +{ + SpiFlashEmulator emu(10); + esp_err_t result; + shared_ptr handle; + + handle = nvs::open_nvs_handle_from_partition("test", "ns_1", NVS_READWRITE, &result); + bool result_expected = result == ESP_ERR_NVS_NOT_INITIALIZED || result == ESP_ERR_NVS_PART_NOT_FOUND; + CHECK(result_expected); + CHECK(!handle); +} + +TEST_CASE("NVSHandleSimple CXX api open successful", "[nvs cxx]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10, "test"); + esp_err_t result; + shared_ptr handle; + + REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0); + + handle = nvs::open_nvs_handle_from_partition("test", "ns_1", NVS_READWRITE, &result); + CHECK(result == ESP_OK); + CHECK(handle); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1); + + handle.reset(); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0); + + nvs::NVSPartitionManager::get_instance()->deinit_partition("test"); +} + +TEST_CASE("NVSHandleSimple CXX api open default part successful", "[nvs cxx]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10); + esp_err_t result; + shared_ptr handle; + + REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0); + + handle = nvs::open_nvs_handle("ns_1", NVS_READWRITE, &result); + CHECK(result == ESP_OK); + CHECK(handle); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1); + + handle.reset(); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0); + + nvs::NVSPartitionManager::get_instance()->deinit_partition("nvs"); +} + +TEST_CASE("NVSHandleSimple CXX api open default part ns NULL", "[nvs cxx]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10); + esp_err_t result; + shared_ptr handle; + + REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0); + + handle = nvs::open_nvs_handle(nullptr, NVS_READWRITE, &result); + CHECK(result == ESP_ERR_INVALID_ARG); + CHECK(!handle); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0); + + nvs::NVSPartitionManager::get_instance()->deinit_partition("nvs"); +} + +TEST_CASE("NVSHandleSimple CXX api read/write string", "[nvs cxx]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10); + char read_buffer [256]; + esp_err_t result; + shared_ptr handle; + + REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0); + + handle = nvs::open_nvs_handle("test_ns", NVS_READWRITE, &result); + CHECK(result == ESP_OK); + REQUIRE(handle); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1); + + CHECK(handle->set_string("test", "test string") == ESP_OK); + CHECK(handle->commit() == ESP_OK); + CHECK(handle->get_string("test", read_buffer, sizeof(read_buffer)) == ESP_OK); + + CHECK(string(read_buffer) == "test string"); + + nvs::NVSPartitionManager::get_instance()->deinit_partition("nvs"); +} + +TEST_CASE("NVSHandleSimple CXX api read/write blob", "[nvs cxx]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10); + const char blob [6] = {15, 16, 17, 18, 19}; + char read_blob[6] = {0}; + esp_err_t result; + shared_ptr handle; + + REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0); + + handle = nvs::open_nvs_handle("test_ns", NVS_READWRITE, &result); + CHECK(result == ESP_OK); + REQUIRE(handle); + + CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1); + + CHECK(handle->set_blob("test", blob, sizeof(blob)) == ESP_OK); + CHECK(handle->commit() == ESP_OK); + CHECK(handle->get_blob("test", read_blob, sizeof(read_blob)) == ESP_OK); + + CHECK(vector(blob, blob + sizeof(blob)) == vector(read_blob, read_blob + sizeof(read_blob))); + + nvs::NVSPartitionManager::get_instance()->deinit_partition("nvs"); +} diff --git a/components/nvs_flash/test_nvs_host/test_nvs_handle.cpp b/components/nvs_flash/test_nvs_host/test_nvs_handle.cpp new file mode 100644 index 000000000..d9f709e7a --- /dev/null +++ b/components/nvs_flash/test_nvs_host/test_nvs_handle.cpp @@ -0,0 +1,281 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "catch.hpp" +#include +#include +#include "nvs_test_api.h" +#include "nvs_handle_simple.hpp" +#include "nvs_partition_manager.hpp" +#include "spi_flash_emulation.h" + +#include "test_fixtures.hpp" + +#include +#include + +using namespace std; +using namespace nvs; + +TEST_CASE("NVSHandleSimple closes its reference in PartitionManager", "[partition_mgr]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10, "test"); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle) == ESP_OK); + + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 1); + + delete handle; + + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0); + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK); + +} + +TEST_CASE("NVSHandleSimple multiple open and closes with PartitionManager", "[partition_mgr]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10, "test"); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0); + + NVSHandleSimple *handle1; + NVSHandleSimple *handle2; + + REQUIRE(NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle1) == ESP_OK); + + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 1); + + REQUIRE(NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle2) == ESP_OK); + + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 2); + + delete handle1; + + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 1); + + delete handle2; + + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0); + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK); + +} + +TEST_CASE("NVSHandleSimple readonly fails", "[partition_mgr]") +{ + PartitionEmulationFixture f(0, 10); + + NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME); + NVSHandleSimple *handle_1; + NVSHandleSimple *handle_2; + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + CHECK(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK); + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0); + + // first, creating namespace... + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle_1) == ESP_OK); + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 1); + + delete handle_1; + + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0); + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READONLY, &handle_2) == ESP_OK); + CHECK(handle_2->set_item("key", 47) == ESP_ERR_NVS_READ_ONLY); + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 1); + + delete handle_2; + + CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0); + // without deinit it affects "nvs api tests" + CHECK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); +} + +TEST_CASE("NVSHandleSimple set/get char", "[partition_mgr]") +{ + enum class TestEnum : char { + FOO = -1, + BEER, + BAR + }; + + PartitionEmulationFixture f(0, 10); + + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK); + + char test_e = 'a'; + char test_e_read = 'z'; + + CHECK(handle->set_item("key", test_e) == ESP_OK); + + CHECK(handle->get_item("key", test_e_read) == ESP_OK); + CHECK(test_e == test_e_read); + + delete handle; + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); +} + +TEST_CASE("NVSHandleSimple correctly sets/gets int enum", "[partition_mgr]") +{ + enum class TestEnum : int { + FOO, + BAR + }; + + PartitionEmulationFixture f(0, 10); + + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK); + + TestEnum test_e = TestEnum::BAR; + TestEnum test_e_read = TestEnum::FOO; + + CHECK(handle->set_item("key", test_e) == ESP_OK); + + CHECK(handle->get_item("key", test_e_read) == ESP_OK); + CHECK(test_e == test_e_read); + + delete handle; + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); +} + +TEST_CASE("NVSHandleSimple correctly sets/gets int enum with negative values", "[partition_mgr]") +{ + enum class TestEnum : int { + FOO = -1, + BEER, + BAR + }; + + PartitionEmulationFixture f(0, 10); + + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK); + + TestEnum test_e = TestEnum::FOO; + TestEnum test_e_read = TestEnum::BEER; + + CHECK(handle->set_item("key", test_e) == ESP_OK); + + CHECK(handle->get_item("key", test_e_read) == ESP_OK); + CHECK(test_e == test_e_read); + + delete handle; + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); +} + +TEST_CASE("NVSHandleSimple correctly sets/gets uint8_t enum", "[partition_mgr]") +{ + enum class TestEnum : uint8_t { + FOO, + BAR + }; + + PartitionEmulationFixture f(0, 10); + + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK); + + TestEnum test_e = TestEnum::BAR; + TestEnum test_e_read = TestEnum::FOO; + + CHECK(handle->set_item("key", test_e) == ESP_OK); + + CHECK(handle->get_item("key", test_e_read) == ESP_OK); + CHECK(test_e == test_e_read); + + delete handle; + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); +} + +TEST_CASE("NVSHandleSimple correctly sets/gets char enum", "[partition_mgr]") +{ + enum class TestEnum : char { + FOO = -1, + BEER, + BAR + }; + + PartitionEmulationFixture f(0, 10); + + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK); + + TestEnum test_e = TestEnum::BAR; + TestEnum test_e_read = TestEnum::FOO; + + CHECK(handle->set_item("key", test_e) == ESP_OK); + + CHECK(handle->get_item("key", test_e_read) == ESP_OK); + CHECK(test_e == test_e_read); + + delete handle; + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK); +} diff --git a/components/nvs_flash/test_nvs_host/test_nvs_initialization.cpp b/components/nvs_flash/test_nvs_host/test_nvs_initialization.cpp new file mode 100644 index 000000000..7731d1da5 --- /dev/null +++ b/components/nvs_flash/test_nvs_host/test_nvs_initialization.cpp @@ -0,0 +1,46 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "catch.hpp" +#include "nvs_partition_manager.hpp" +#include "spi_flash_emulation.h" +#include "esp_partition.h" +#include "nvs.h" +#include + +using namespace nvs; + +TEST_CASE("nvs_flash_init_partition_ptr fails due to nullptr arg", "[nvs_custom_part]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + SpiFlashEmulator emu(10); + + CHECK(nvs_flash_init_partition_ptr(nullptr) == ESP_ERR_INVALID_ARG); +} + +TEST_CASE("nvs_flash_init_partition_ptr inits one partition", "[nvs_custom_part]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + SpiFlashEmulator emu(10); + + esp_partition_t partition = {}; + strcpy(partition.label, "test"); + partition.address = NVS_FLASH_SECTOR * SPI_FLASH_SEC_SIZE; + partition.size = NVS_FLASH_SECTOR_COUNT_MIN * SPI_FLASH_SEC_SIZE; + + CHECK(nvs_flash_init_partition_ptr(&partition) == ESP_OK); + CHECK(NVSPartitionManager::get_instance()->lookup_storage_from_name("test") != nullptr); + CHECK(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK); +} diff --git a/components/nvs_flash/test_nvs_host/test_nvs_partition.cpp b/components/nvs_flash/test_nvs_host/test_nvs_partition.cpp new file mode 100644 index 000000000..4385b9a6d --- /dev/null +++ b/components/nvs_flash/test_nvs_host/test_nvs_partition.cpp @@ -0,0 +1,55 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "catch.hpp" +#include +#include +#include "nvs_test_api.h" +#include "nvs_handle_simple.hpp" +#include "nvs_partition.hpp" +#include "spi_flash_emulation.h" + +#include "test_fixtures.hpp" + +#include + +using namespace std; +using namespace nvs; + +TEST_CASE("encrypted partition read size must be item size", "[nvs]") +{ + char foo [32] = { }; + nvs_sec_cfg_t xts_cfg; + for(int count = 0; count < NVS_KEY_SIZE; count++) { + xts_cfg.eky[count] = 0x11; + xts_cfg.tky[count] = 0x22; + } + EncryptedPartitionFixture fix(&xts_cfg); + + CHECK(fix.part.read(0, foo, sizeof (foo) -1) == ESP_ERR_INVALID_SIZE); +} + +TEST_CASE("encrypted partition write size must be mod item size", "[nvs]") +{ + char foo [64] = { }; + nvs_sec_cfg_t xts_cfg; + for(int count = 0; count < NVS_KEY_SIZE; count++) { + xts_cfg.eky[count] = 0x11; + xts_cfg.tky[count] = 0x22; + } + EncryptedPartitionFixture fix(&xts_cfg); + + CHECK(fix.part.write(0, foo, sizeof (foo) -1) == ESP_ERR_INVALID_SIZE); + CHECK(fix.part.write(0, foo, sizeof (foo)) == ESP_OK); + CHECK(fix.part.write(0, foo, sizeof (foo) * 2) == ESP_OK); +} diff --git a/components/nvs_flash/test_nvs_host/test_nvs_storage.cpp b/components/nvs_flash/test_nvs_host/test_nvs_storage.cpp new file mode 100644 index 000000000..a0ace089c --- /dev/null +++ b/components/nvs_flash/test_nvs_host/test_nvs_storage.cpp @@ -0,0 +1,60 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "catch.hpp" +#include +#include "nvs_test_api.h" +#include "nvs_storage.hpp" +#include "nvs_partition_manager.hpp" +#include "spi_flash_emulation.h" + +#include "test_fixtures.hpp" + +#include + +using namespace std; +using namespace nvs; + +TEST_CASE("Storage iterator recognizes blob with VerOffset::VER_1_OFFSET", "[nvs_storage]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10, "test"); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + uint8_t blob [] = {0x0, 0x1, 0x2, 0x3}; + uint8_t blob_new [] = {0x3, 0x2, 0x1, 0x0}; + Storage *storage = NVSPartitionManager::get_instance()->lookup_storage_from_name("test"); + uint8_t ns_index; + storage->createOrOpenNamespace("test_ns", true, ns_index); + + CHECK(storage->writeItem(ns_index, ItemType::BLOB, "test_blob", blob, sizeof(blob)) == ESP_OK); + + // changing provokes a blob with version offset 1 (VerOffset::VER_1_OFFSET) + CHECK(storage->writeItem(ns_index, ItemType::BLOB, "test_blob", blob_new, sizeof(blob_new)) == ESP_OK); + + nvs_opaque_iterator_t it; + it.storage = storage; + it.type = NVS_TYPE_ANY; + + // Central check: does the iterator recognize the blob with version 1? + REQUIRE(storage->findEntry(&it, "test_ns")); + + CHECK(string(it.entry_info.namespace_name) == string("test_ns")); + CHECK(string(it.entry_info.key) == string("test_blob")); + CHECK(it.entry_info.type == NVS_TYPE_BLOB); + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK); +} diff --git a/components/nvs_flash/test_nvs_host/test_partition_manager.cpp b/components/nvs_flash/test_nvs_host/test_partition_manager.cpp new file mode 100644 index 000000000..b2db3a9cf --- /dev/null +++ b/components/nvs_flash/test_nvs_host/test_partition_manager.cpp @@ -0,0 +1,91 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "catch.hpp" +#include +#include +#include "nvs_test_api.h" +#include "nvs_handle_simple.hpp" +#include "nvs_partition_manager.hpp" +#include "spi_flash_emulation.h" +#include "nvs_test_api.h" + +#include "test_fixtures.hpp" + +using namespace nvs; + +TEST_CASE("Partition manager initializes storage", "[partition_mgr]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10, "test"); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK); + CHECK(NVSPartitionManager::get_instance()->lookup_storage_from_name("test") != nullptr); + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(f.part.get_partition_name()) == ESP_OK); +} + +TEST_CASE("Partition manager de-initializes storage", "[partition_mgr]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10, "test"); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK); + CHECK(NVSPartitionManager::get_instance()->lookup_storage_from_name("test") != nullptr); + CHECK(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK); + CHECK(NVSPartitionManager::get_instance()->lookup_storage_from_name("test") == nullptr); +} + +TEST_CASE("Partition manager initializes multiple partitions", "[partition_mgr]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + SpiFlashEmulator emu(10); + PartitionEmulation part_0(&emu, NVS_FLASH_SECTOR * SPI_FLASH_SEC_SIZE, NVS_FLASH_SECTOR_COUNT_MIN * SPI_FLASH_SEC_SIZE, "test1"); + PartitionEmulation part_1(&emu, NVS_FLASH_SECTOR * SPI_FLASH_SEC_SIZE, NVS_FLASH_SECTOR_COUNT_MIN * SPI_FLASH_SEC_SIZE, "test2"); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&part_0, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + // TODO: why does this work, actually? same sectors used as above + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&part_1, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + Storage *storage1 = NVSPartitionManager::get_instance()->lookup_storage_from_name("test1"); + REQUIRE(storage1 != nullptr); + Storage *storage2 = NVSPartitionManager::get_instance()->lookup_storage_from_name("test2"); + REQUIRE(storage2 != nullptr); + + CHECK(storage1 != storage2); + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(part_0.get_partition_name()) == ESP_OK); + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(part_1.get_partition_name()) == ESP_OK); +} + +TEST_CASE("Partition manager invalidates handle on partition de-init", "[partition_mgr]") +{ + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + PartitionEmulationFixture f(0, 10, "test"); + + REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) + == ESP_OK); + + NVSHandleSimple *handle; + REQUIRE(NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle) == ESP_OK); + CHECK(handle->erase_all() == ESP_OK); + + REQUIRE(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK); + + CHECK(handle->erase_all() == ESP_ERR_NVS_INVALID_HANDLE); + + delete handle; +} diff --git a/components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp b/components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp index 0c77aa966..64ea96b17 100644 --- a/components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp +++ b/components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp @@ -13,7 +13,9 @@ // limitations under the License. #include "catch.hpp" #include "esp_spi_flash.h" +#include "esp_partition.h" #include "spi_flash_emulation.h" +#include using namespace std; @@ -23,14 +25,21 @@ bool range_empty_n(Tit it_begin, size_t n) return all_of(it_begin, it_begin + n, bind(equal_to(), placeholders::_1, 0xffffffff)); } +struct FlashEmuFixture { + FlashEmuFixture(size_t sectors) : esp_part(), emu(sectors) { } + + esp_partition_t esp_part; + SpiFlashEmulator emu; +}; + TEST_CASE("flash starts with all bytes == 0xff", "[spi_flash_emu]") { - SpiFlashEmulator emu(4); + FlashEmuFixture f(4); uint8_t sector[SPI_FLASH_SEC_SIZE]; for (int i = 0; i < 4; ++i) { - CHECK(spi_flash_read(0, sector, sizeof(sector)) == ESP_OK); + CHECK(esp_partition_read(&f.esp_part, 0, sector, sizeof(sector)) == ESP_OK); for (auto v: sector) { CHECK(v == 0xff); } @@ -39,116 +48,138 @@ TEST_CASE("flash starts with all bytes == 0xff", "[spi_flash_emu]") TEST_CASE("invalid writes are checked", "[spi_flash_emu]") { - SpiFlashEmulator emu(1); + FlashEmuFixture f(1); uint32_t val = 0; - CHECK(spi_flash_write(0, &val, 4) == ESP_OK); + CHECK(esp_partition_write(&f.esp_part, 0, &val, 4) == ESP_OK); val = 1; - CHECK(spi_flash_write(0, &val, 4) == ESP_ERR_FLASH_OP_FAIL); + CHECK(esp_partition_write(&f.esp_part, 0, &val, 4) == ESP_ERR_FLASH_OP_FAIL); } TEST_CASE("out of bounds writes fail", "[spi_flash_emu]") { - SpiFlashEmulator emu(4); + FlashEmuFixture f(4); uint32_t vals[8]; std::fill_n(vals, 8, 0); - CHECK(spi_flash_write(0, vals, sizeof(vals)) == ESP_OK); + CHECK(esp_partition_write(&f.esp_part, 0, &vals, sizeof(vals)) == ESP_OK); - CHECK(spi_flash_write(4*4096 - sizeof(vals), vals, sizeof(vals)) == ESP_OK); + CHECK(esp_partition_write(&f.esp_part, 4*4096 - sizeof(vals), &vals, sizeof(vals)) == ESP_OK); - CHECK(spi_flash_write(4*4096 - sizeof(vals) + 4, vals, sizeof(vals)) == ESP_ERR_FLASH_OP_FAIL); + CHECK(esp_partition_write(&f.esp_part, 4*4096 - sizeof(vals) + 4, &vals, sizeof(vals)) == ESP_ERR_FLASH_OP_FAIL); } - TEST_CASE("after erase the sector is set to 0xff", "[spi_flash_emu]") { - SpiFlashEmulator emu(4); + FlashEmuFixture f(4); uint32_t val1 = 0xab00cd12; - CHECK(spi_flash_write(0, &val1, sizeof(val1)) == ESP_OK); + CHECK(esp_partition_write(&f.esp_part, 0, &val1, sizeof(val1)) == ESP_OK); uint32_t val2 = 0x5678efab; - CHECK(spi_flash_write(4096 - 4, &val2, sizeof(val2)) == ESP_OK); + CHECK(esp_partition_write(&f.esp_part, 4096 - 4, &val2, sizeof(val2)) == ESP_OK); + + CHECK(f.emu.words()[0] == val1); + CHECK(range_empty_n(f.emu.words() + 1, 4096 / 4 - 2)); + CHECK(f.emu.words()[4096 / 4 - 1] == val2); + + CHECK(esp_partition_erase_range(&f.esp_part, 0, SPI_FLASH_SEC_SIZE) == ESP_OK); + + CHECK(f.emu.words()[0] == 0xffffffff); + CHECK(range_empty_n(f.emu.words() + 1, 4096 / 4 - 2)); + CHECK(f.emu.words()[4096 / 4 - 1] == 0xffffffff); +} + +TEST_CASE("EMU raw read function works", "[spi_flash_emu]") +{ + FlashEmuFixture f(4); + uint32_t value = 0xdeadbeef; + uint32_t read_value = 0; + CHECK(esp_partition_write(&f.esp_part, 0, &value, sizeof(value)) == ESP_OK); + + CHECK(esp_partition_read_raw(&f.esp_part, 0, &read_value, sizeof(&read_value)) == ESP_OK); + + CHECK(read_value == 0xdeadbeef); +} - CHECK(emu.words()[0] == val1); - CHECK(range_empty_n(emu.words() + 1, 4096 / 4 - 2)); - CHECK(emu.words()[4096 / 4 - 1] == val2); +TEST_CASE("EMU raw write function works", "[spi_flash_emu]") +{ + FlashEmuFixture f(4); + uint32_t value = 0xdeadbeef; + uint32_t read_value = 0; + CHECK(esp_partition_write_raw(&f.esp_part, 0, &value, sizeof(value)) == ESP_OK); - CHECK(spi_flash_erase_sector(0) == ESP_OK); + CHECK(esp_partition_read(&f.esp_part, 0, &read_value, sizeof(&read_value)) == ESP_OK); - CHECK(emu.words()[0] == 0xffffffff); - CHECK(range_empty_n(emu.words() + 1, 4096 / 4 - 2)); - CHECK(emu.words()[4096 / 4 - 1] == 0xffffffff); + CHECK(read_value == 0xdeadbeef); } TEST_CASE("read/write/erase operation times are calculated correctly", "[spi_flash_emu]") { - SpiFlashEmulator emu(1); + FlashEmuFixture f(1); uint8_t data[512]; - spi_flash_read(0, data, 4); - CHECK(emu.getTotalTime() == 7); - CHECK(emu.getReadOps() == 1); - CHECK(emu.getReadBytes() == 4); - emu.clearStats(); - spi_flash_read(0, data, 8); - CHECK(emu.getTotalTime() == 5); - CHECK(emu.getReadOps() == 1); - CHECK(emu.getReadBytes() == 8); - emu.clearStats(); - spi_flash_read(0, data, 16); - CHECK(emu.getTotalTime() == 6); - CHECK(emu.getReadOps() == 1); - CHECK(emu.getReadBytes() == 16); - emu.clearStats(); - spi_flash_read(0, data, 128); - CHECK(emu.getTotalTime() == 18); - CHECK(emu.getReadOps() == 1); - CHECK(emu.getReadBytes() == 128); - emu.clearStats(); - spi_flash_read(0, data, 256); - CHECK(emu.getTotalTime() == 32); - emu.clearStats(); - spi_flash_read(0, data, (128+256)/2); - CHECK(emu.getTotalTime() == (18+32)/2); - emu.clearStats(); - - spi_flash_write(0, data, 4); - CHECK(emu.getTotalTime() == 19); - CHECK(emu.getWriteOps() == 1); - CHECK(emu.getWriteBytes() == 4); - emu.clearStats(); - CHECK(emu.getWriteOps() == 0); - CHECK(emu.getWriteBytes() == 0); - spi_flash_write(0, data, 8); - CHECK(emu.getTotalTime() == 23); - emu.clearStats(); - spi_flash_write(0, data, 16); - CHECK(emu.getTotalTime() == 35); - CHECK(emu.getWriteOps() == 1); - CHECK(emu.getWriteBytes() == 16); - emu.clearStats(); - spi_flash_write(0, data, 128); - CHECK(emu.getTotalTime() == 205); - emu.clearStats(); - spi_flash_write(0, data, 256); - CHECK(emu.getTotalTime() == 417); - emu.clearStats(); - spi_flash_write(0, data, (128+256)/2); - CHECK(emu.getTotalTime() == (205+417)/2); - emu.clearStats(); - - spi_flash_erase_sector(0); - CHECK(emu.getEraseOps() == 1); - CHECK(emu.getTotalTime() == 37142); + esp_partition_read(&f.esp_part, 0, data, 4); + CHECK(f.emu.getTotalTime() == 7); + CHECK(f.emu.getReadOps() == 1); + CHECK(f.emu.getReadBytes() == 4); + f.emu.clearStats(); + esp_partition_read(&f.esp_part, 0, data, 8); + CHECK(f.emu.getTotalTime() == 5); + CHECK(f.emu.getReadOps() == 1); + CHECK(f.emu.getReadBytes() == 8); + f.emu.clearStats(); + esp_partition_read(&f.esp_part, 0, data, 16); + CHECK(f.emu.getTotalTime() == 6); + CHECK(f.emu.getReadOps() == 1); + CHECK(f.emu.getReadBytes() == 16); + f.emu.clearStats(); + esp_partition_read(&f.esp_part, 0, data, 128); + CHECK(f.emu.getTotalTime() == 18); + CHECK(f.emu.getReadOps() == 1); + CHECK(f.emu.getReadBytes() == 128); + f.emu.clearStats(); + esp_partition_read(&f.esp_part, 0, data, 256); + CHECK(f.emu.getTotalTime() == 32); + f.emu.clearStats(); + esp_partition_read(&f.esp_part, 0, data, (128+256)/2); + CHECK(f.emu.getTotalTime() == (18+32)/2); + f.emu.clearStats(); + + esp_partition_write(&f.esp_part, 0, data, 4); + CHECK(f.emu.getTotalTime() == 19); + CHECK(f.emu.getWriteOps() == 1); + CHECK(f.emu.getWriteBytes() == 4); + f.emu.clearStats(); + CHECK(f.emu.getWriteOps() == 0); + CHECK(f.emu.getWriteBytes() == 0); + esp_partition_write(&f.esp_part, 0, data, 8); + CHECK(f.emu.getTotalTime() == 23); + f.emu.clearStats(); + esp_partition_write(&f.esp_part, 0, data, 16); + CHECK(f.emu.getTotalTime() == 35); + CHECK(f.emu.getWriteOps() == 1); + CHECK(f.emu.getWriteBytes() == 16); + f.emu.clearStats(); + esp_partition_write(&f.esp_part, 0, data, 128); + CHECK(f.emu.getTotalTime() == 205); + f.emu.clearStats(); + esp_partition_write(&f.esp_part, 0, data, 256); + CHECK(f.emu.getTotalTime() == 417); + f.emu.clearStats(); + esp_partition_write(&f.esp_part, 0, data, (128+256)/2); + CHECK(f.emu.getTotalTime() == (205+417)/2); + f.emu.clearStats(); + + esp_partition_erase_range(&f.esp_part, 0, SPI_FLASH_SEC_SIZE); + CHECK(f.emu.getEraseOps() == 1); + CHECK(f.emu.getTotalTime() == 37142); } TEST_CASE("data is randomized predictably", "[spi_flash_emu]") { SpiFlashEmulator emu1(3); emu1.randomize(0x12345678); - + SpiFlashEmulator emu2(3); emu2.randomize(0x12345678); - + CHECK(std::equal(emu1.bytes(), emu1.bytes() + emu1.size(), emu2.bytes())); } - From f25a7ad205ba29608ae65833737134efee5872f8 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 23 Jul 2021 17:21:22 +0800 Subject: [PATCH 20/57] feat(nvs_flash): Modify for ESP8266 --- components/esp8266/include/esp_attr.h | 6 ++++++ components/esp8266/source/phy_init.c | 12 ++++++------ components/esp8266/source/system_api.c | 4 ++-- components/lwip/port/esp8266/netif/dhcp_state.c | 1 - components/nvs_flash/Kconfig | 12 ------------ .../host_test/fixtures/test_fixtures.hpp | 4 ++-- components/nvs_flash/mock/int/crc.cpp | 2 +- components/nvs_flash/mock/int/crc.h | 2 +- components/nvs_flash/src/nvs_api.cpp | 12 ++++++------ components/nvs_flash/src/nvs_page.cpp | 4 ++-- components/nvs_flash/src/nvs_partition.cpp | 4 ++-- components/nvs_flash/src/nvs_partition.hpp | 4 ++-- components/nvs_flash/src/nvs_types.cpp | 16 ++++++++-------- components/nvs_flash/test/test_nvs.c | 1 - .../test_nvs_host/spi_flash_emulation.cpp | 4 ++-- .../test_nvs_host/test_spi_flash_emulation.cpp | 4 ++-- 16 files changed, 42 insertions(+), 50 deletions(-) delete mode 100644 components/nvs_flash/Kconfig diff --git a/components/esp8266/include/esp_attr.h b/components/esp8266/include/esp_attr.h index f21fb7a54..d5b14d38b 100644 --- a/components/esp8266/include/esp_attr.h +++ b/components/esp8266/include/esp_attr.h @@ -68,4 +68,10 @@ #define _COUNTER_STRINGIFY(COUNTER) #COUNTER +#ifdef IDF_CI_BUILD +#define IDF_DEPRECATED(REASON) __attribute__((deprecated(REASON))) +#else +#define IDF_DEPRECATED(REASON) +#endif + #endif /* __ESP_ATTR_H__ */ diff --git a/components/esp8266/source/phy_init.c b/components/esp8266/source/phy_init.c index 722dec55c..21563f8bb 100644 --- a/components/esp8266/source/phy_init.c +++ b/components/esp8266/source/phy_init.c @@ -204,15 +204,15 @@ static const char* PHY_NAMESPACE = "phy"; static const char* PHY_CAL_DATA_KEY = "cal_data"; static const char* PHY_RX_GAIN_DC_TABLE_KEY = "dc_table"; -static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, +static esp_err_t load_cal_data_from_nvs_handle(nvs_handle_t handle, esp_phy_calibration_data_t* out_cal_data); -static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, +static esp_err_t store_cal_data_to_nvs_handle(nvs_handle_t handle, const esp_phy_calibration_data_t* cal_data); esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data) { - nvs_handle handle; + nvs_handle_t handle; esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle); if (err == ESP_ERR_NVS_NOT_INITIALIZED) { @@ -230,7 +230,7 @@ esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_dat esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data) { - nvs_handle handle; + nvs_handle_t handle; esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READWRITE, &handle); if (err != ESP_OK) { @@ -243,7 +243,7 @@ esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_da } } -static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, +static esp_err_t load_cal_data_from_nvs_handle(nvs_handle_t handle, esp_phy_calibration_data_t* out_cal_data) { esp_err_t err; @@ -278,7 +278,7 @@ static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, return ESP_OK; } -static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, +static esp_err_t store_cal_data_to_nvs_handle(nvs_handle_t handle, const esp_phy_calibration_data_t* cal_data) { esp_err_t err; diff --git a/components/esp8266/source/system_api.c b/components/esp8266/source/system_api.c index 080514e47..1a0c1aad3 100644 --- a/components/esp8266/source/system_api.c +++ b/components/esp8266/source/system_api.c @@ -136,7 +136,7 @@ static const char *BACKUP_MAC_DATA_KEY = "backup_mac_data"; static esp_err_t load_backup_mac_data(uint8_t *mac) { esp_err_t err; - nvs_handle handle; + nvs_handle_t handle; uint32_t efuse[4]; uint8_t efuse_crc = 0; uint8_t calc_crc = 0; @@ -221,7 +221,7 @@ static esp_err_t load_backup_mac_data(uint8_t *mac) static esp_err_t store_backup_mac_data() { esp_err_t err; - nvs_handle handle; + nvs_handle_t handle; uint32_t efuse[4]; efuse[0] = REG_READ(EFUSE_DATA0_REG); efuse[1] = REG_READ(EFUSE_DATA1_REG); diff --git a/components/lwip/port/esp8266/netif/dhcp_state.c b/components/lwip/port/esp8266/netif/dhcp_state.c index 6ae00d700..8e2e3d9f3 100644 --- a/components/lwip/port/esp8266/netif/dhcp_state.c +++ b/components/lwip/port/esp8266/netif/dhcp_state.c @@ -31,7 +31,6 @@ static const char *interface_key[] = {"IF_STA", "IF_AP", "IF_ETH", "IF_TEST"}; _Static_assert(sizeof(interface_key) / sizeof(char*) == TCPIP_ADAPTER_IF_MAX, "Number interface keys differs from number of interfaces"); -typedef nvs_handle nvs_handle_t; bool dhcp_ip_addr_restore(void *netif) { nvs_handle_t nvs; diff --git a/components/nvs_flash/Kconfig b/components/nvs_flash/Kconfig deleted file mode 100644 index 98cf97987..000000000 --- a/components/nvs_flash/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -menu "NVS" - - config NVS_ENCRYPTION - bool "Enable NVS encryption" - default y - depends on SECURE_FLASH_ENC_ENABLED - help - This option enables encryption for NVS. When enabled, AES-XTS is used to encrypt - the complete NVS data, except the page headers. It requires XTS encryption keys - to be stored in an encrypted partition. This means enabling flash encryption is - a pre-requisite for this feature. -endmenu diff --git a/components/nvs_flash/host_test/fixtures/test_fixtures.hpp b/components/nvs_flash/host_test/fixtures/test_fixtures.hpp index 06b12ce17..0baef7d3f 100644 --- a/components/nvs_flash/host_test/fixtures/test_fixtures.hpp +++ b/components/nvs_flash/host_test/fixtures/test_fixtures.hpp @@ -52,7 +52,7 @@ class PartitionMock : public nvs::Partition { esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override { - return esp_partition_read_raw(&partition, src_offset, dst, size); + return esp_partition_read(&partition, src_offset, dst, size); } esp_err_t read(size_t src_offset, void* dst, size_t size) override @@ -62,7 +62,7 @@ class PartitionMock : public nvs::Partition { esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override { - return esp_partition_write_raw(&partition, dst_offset, src, size); + return esp_partition_write(&partition, dst_offset, src, size); } esp_err_t write(size_t dst_offset, const void* src, size_t size) override diff --git a/components/nvs_flash/mock/int/crc.cpp b/components/nvs_flash/mock/int/crc.cpp index 5c1b74564..5098a1415 100644 --- a/components/nvs_flash/mock/int/crc.cpp +++ b/components/nvs_flash/mock/int/crc.cpp @@ -52,7 +52,7 @@ static const unsigned int crc32_le_table[256] = { -extern "C" uint32_t esp_rom_crc32_le(unsigned int crc, unsigned char const * buf,unsigned int len) +extern "C" uint32_t crc32_le(unsigned int crc, unsigned char const * buf,unsigned int len) { unsigned int i; crc = ~crc; diff --git a/components/nvs_flash/mock/int/crc.h b/components/nvs_flash/mock/int/crc.h index f675da327..405295f8b 100644 --- a/components/nvs_flash/mock/int/crc.h +++ b/components/nvs_flash/mock/int/crc.h @@ -24,7 +24,7 @@ extern "C" { * Mock function to replace ESP ROM function used in IDF with a Linux implementation. * Note: the name MUST have the prefix esp_rom_* since tools/ci/check_rom_apis.sh checks and complains otherwise. */ -uint32_t esp_rom_crc32_le(uint32_t crc, const uint8_t* buf, size_t len); +uint32_t crc32_le(uint32_t crc, const uint8_t* buf, size_t len); #ifdef __cplusplus } diff --git a/components/nvs_flash/src/nvs_api.cpp b/components/nvs_flash/src/nvs_api.cpp index fe58ccd2c..8d0848c48 100644 --- a/components/nvs_flash/src/nvs_api.cpp +++ b/components/nvs_flash/src/nvs_api.cpp @@ -27,7 +27,7 @@ #include "crc.h" #define ESP_LOGD(...) #else // LINUX_TARGET -#include +#include // Uncomment this line to force output from this module // #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG @@ -586,13 +586,13 @@ extern "C" esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, n * But the read is decrypted through flash encryption engine. This allows unique NVS encryption configuration, * as flash encryption key is randomly generated per device. */ - err = esp_partition_write_raw(partition, 0, cfg->eky, NVS_KEY_SIZE); + err = esp_partition_write(partition, 0, cfg->eky, NVS_KEY_SIZE); if(err != ESP_OK) { return err; } /* Write without encryption, see note above */ - err = esp_partition_write_raw(partition, NVS_KEY_SIZE, cfg->tky, NVS_KEY_SIZE); + err = esp_partition_write(partition, NVS_KEY_SIZE, cfg->tky, NVS_KEY_SIZE); if(err != ESP_OK) { return err; } @@ -638,17 +638,17 @@ extern "C" esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partitio return true; }; - auto err = esp_partition_read_raw(partition, 0, eky_raw, NVS_KEY_SIZE); + auto err = esp_partition_read(partition, 0, eky_raw, NVS_KEY_SIZE); if(err != ESP_OK) { return err; } - err = esp_partition_read_raw(partition, NVS_KEY_SIZE, tky_raw, NVS_KEY_SIZE); + err = esp_partition_read(partition, NVS_KEY_SIZE, tky_raw, NVS_KEY_SIZE); if(err != ESP_OK) { return err; } - err = esp_partition_read_raw(partition, 2 * NVS_KEY_SIZE, &crc_raw, 4); + err = esp_partition_read(partition, 2 * NVS_KEY_SIZE, &crc_raw, 4); if(err != ESP_OK) { return err; } diff --git a/components/nvs_flash/src/nvs_page.cpp b/components/nvs_flash/src/nvs_page.cpp index 2f72a2090..600759fe8 100644 --- a/components/nvs_flash/src/nvs_page.cpp +++ b/components/nvs_flash/src/nvs_page.cpp @@ -15,7 +15,7 @@ #if defined(LINUX_TARGET) #include "crc.h" #else -#include +#include #endif #include #include @@ -27,7 +27,7 @@ Page::Page() : mPartition(nullptr) { } uint32_t Page::Header::calculateCrc32() { - return esp_rom_crc32_le(0xffffffff, + return crc32_le(0xffffffff, reinterpret_cast(this) + offsetof(Header, mSeqNumber), offsetof(Header, mCrc32) - offsetof(Header, mSeqNumber)); } diff --git a/components/nvs_flash/src/nvs_partition.cpp b/components/nvs_flash/src/nvs_partition.cpp index f1b7d36d2..9ee8d378c 100644 --- a/components/nvs_flash/src/nvs_partition.cpp +++ b/components/nvs_flash/src/nvs_partition.cpp @@ -33,7 +33,7 @@ const char *NVSPartition::get_partition_name() esp_err_t NVSPartition::read_raw(size_t src_offset, void* dst, size_t size) { - return esp_partition_read_raw(mESPPartition, src_offset, dst, size); + return esp_partition_read(mESPPartition, src_offset, dst, size); } esp_err_t NVSPartition::read(size_t src_offset, void* dst, size_t size) @@ -47,7 +47,7 @@ esp_err_t NVSPartition::read(size_t src_offset, void* dst, size_t size) esp_err_t NVSPartition::write_raw(size_t dst_offset, const void* src, size_t size) { - return esp_partition_write_raw(mESPPartition, dst_offset, src, size); + return esp_partition_write(mESPPartition, dst_offset, src, size); } esp_err_t NVSPartition::write(size_t dst_offset, const void* src, size_t size) diff --git a/components/nvs_flash/src/nvs_partition.hpp b/components/nvs_flash/src/nvs_partition.hpp index 2af3e238e..d5259cdb5 100644 --- a/components/nvs_flash/src/nvs_partition.hpp +++ b/components/nvs_flash/src/nvs_partition.hpp @@ -50,7 +50,7 @@ class NVSPartition : public Partition, public intrusive_list_node const char *get_partition_name() override; /** - * Look into \c esp_partition_read_raw for more details. + * Look into \c esp_partition_read for more details. * * @return * - ESP_OK on success @@ -69,7 +69,7 @@ class NVSPartition : public Partition, public intrusive_list_node esp_err_t read(size_t src_offset, void* dst, size_t size) override; /** - * Look into \c esp_partition_write_raw for more details. + * Look into \c esp_partition_write for more details. * * @return * - ESP_OK on success diff --git a/components/nvs_flash/src/nvs_types.cpp b/components/nvs_flash/src/nvs_types.cpp index 0189dd70b..127e24b88 100644 --- a/components/nvs_flash/src/nvs_types.cpp +++ b/components/nvs_flash/src/nvs_types.cpp @@ -16,7 +16,7 @@ #if defined(LINUX_TARGET) #include "crc.h" #else -#include +#include #endif namespace nvs @@ -25,10 +25,10 @@ uint32_t Item::calculateCrc32() const { uint32_t result = 0xffffffff; const uint8_t* p = reinterpret_cast(this); - result = esp_rom_crc32_le(result, p + offsetof(Item, nsIndex), + result = crc32_le(result, p + offsetof(Item, nsIndex), offsetof(Item, crc32) - offsetof(Item, nsIndex)); - result = esp_rom_crc32_le(result, p + offsetof(Item, key), sizeof(key)); - result = esp_rom_crc32_le(result, p + offsetof(Item, data), sizeof(data)); + result = crc32_le(result, p + offsetof(Item, key), sizeof(key)); + result = crc32_le(result, p + offsetof(Item, data), sizeof(data)); return result; } @@ -36,17 +36,17 @@ uint32_t Item::calculateCrc32WithoutValue() const { uint32_t result = 0xffffffff; const uint8_t* p = reinterpret_cast(this); - result = esp_rom_crc32_le(result, p + offsetof(Item, nsIndex), + result = crc32_le(result, p + offsetof(Item, nsIndex), offsetof(Item, datatype) - offsetof(Item, nsIndex)); - result = esp_rom_crc32_le(result, p + offsetof(Item, key), sizeof(key)); - result = esp_rom_crc32_le(result, p + offsetof(Item, chunkIndex), sizeof(chunkIndex)); + result = crc32_le(result, p + offsetof(Item, key), sizeof(key)); + result = crc32_le(result, p + offsetof(Item, chunkIndex), sizeof(chunkIndex)); return result; } uint32_t Item::calculateCrc32(const uint8_t* data, size_t size) { uint32_t result = 0xffffffff; - result = esp_rom_crc32_le(result, data, size); + result = crc32_le(result, data, size); return result; } diff --git a/components/nvs_flash/test/test_nvs.c b/components/nvs_flash/test/test_nvs.c index b32fa93ba..7e172f5ac 100644 --- a/components/nvs_flash/test/test_nvs.c +++ b/components/nvs_flash/test/test_nvs.c @@ -7,7 +7,6 @@ #include "nvs.h" #include "nvs_flash.h" #include "esp_partition.h" -#include "esp_flash_encrypt.h" #include "esp_log.h" #include #include "esp_system.h" diff --git a/components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp b/components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp index 802256c1a..e5b9ae071 100644 --- a/components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp +++ b/components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp @@ -62,7 +62,7 @@ esp_err_t esp_partition_read(const esp_partition_t* partition, return ESP_OK; } -esp_err_t esp_partition_read_raw(const esp_partition_t* partition, +esp_err_t esp_partition_read(const esp_partition_t* partition, size_t src_offset, void* dst, size_t size) { if (!s_emulator) { @@ -90,7 +90,7 @@ esp_err_t esp_partition_write(const esp_partition_t* partition, return ESP_OK; } -esp_err_t esp_partition_write_raw(const esp_partition_t* partition, +esp_err_t esp_partition_write(const esp_partition_t* partition, size_t dst_offset, const void* src, size_t size) { if (!s_emulator) { diff --git a/components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp b/components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp index 64ea96b17..353e1212a 100644 --- a/components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp +++ b/components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp @@ -95,7 +95,7 @@ TEST_CASE("EMU raw read function works", "[spi_flash_emu]") uint32_t read_value = 0; CHECK(esp_partition_write(&f.esp_part, 0, &value, sizeof(value)) == ESP_OK); - CHECK(esp_partition_read_raw(&f.esp_part, 0, &read_value, sizeof(&read_value)) == ESP_OK); + CHECK(esp_partition_read(&f.esp_part, 0, &read_value, sizeof(&read_value)) == ESP_OK); CHECK(read_value == 0xdeadbeef); } @@ -105,7 +105,7 @@ TEST_CASE("EMU raw write function works", "[spi_flash_emu]") FlashEmuFixture f(4); uint32_t value = 0xdeadbeef; uint32_t read_value = 0; - CHECK(esp_partition_write_raw(&f.esp_part, 0, &value, sizeof(value)) == ESP_OK); + CHECK(esp_partition_write(&f.esp_part, 0, &value, sizeof(value)) == ESP_OK); CHECK(esp_partition_read(&f.esp_part, 0, &read_value, sizeof(&read_value)) == ESP_OK); From 6964300cf930902a5710930a7c8b95a5b09ad701 Mon Sep 17 00:00:00 2001 From: Li Jingyi Date: Fri, 26 Feb 2021 11:53:42 +0800 Subject: [PATCH 21/57] feat(mbedtls): Add CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 and modify makefile for support GMTSSL1.1 --- components/mbedtls/CMakeLists.txt | 14 ++++++++++++++ components/mbedtls/Kconfig | 7 +++++++ components/mbedtls/component.mk | 14 ++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index ea61a5217..b189fe05b 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -17,6 +17,20 @@ get_target_property(src_tls mbedtls SOURCES) list(REMOVE_ITEM src_tls net_sockets.c) set_property(TARGET mbedtls PROPERTY SOURCES ${src_tls}) +if(CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1) +get_target_property(src_tls mbedtls SOURCES) +list(REMOVE_ITEM src_tls ssl_ciphersuites.c ssl_cli.c ssl_tls.c) +set_property(TARGET mbedtls PROPERTY SOURCES ${src_tls}) + +get_target_property(src_crypto mbedcrypto SOURCES) +list(REMOVE_ITEM src_crypto cipher_wrap.c ecdsa.c ecp.c ecp_curves.c oid.c pk_wrap.c) +set_property(TARGET mbedcrypto PROPERTY SOURCES ${src_crypto}) + +get_target_property(src_x509 mbedx509 SOURCES) +list(REMOVE_ITEM src_x509 x509_crt.c) +set_property(TARGET mbedx509 PROPERTY SOURCES ${src_x509}) +endif() + set(mbedtls_targets mbedtls mbedcrypto mbedx509) # Add port files to mbedtls targets diff --git a/components/mbedtls/Kconfig b/components/mbedtls/Kconfig index 0bec091bd..a59579fb9 100644 --- a/components/mbedtls/Kconfig +++ b/components/mbedtls/Kconfig @@ -328,6 +328,13 @@ menu "mbedTLS" depends on MBEDTLS_TLS_ENABLED default y + config MBEDTLS_SSL_PROTO_GMTSSL1_1 + bool "Support GM/T SSL 1.1 protocol" + depends on MBEDTLS_TLS_ENABLED + default n + help + Provisions for GM/T SSL 1.1 support + config MBEDTLS_SSL_PROTO_DTLS bool "Support DTLS protocol (all versions)" default n diff --git a/components/mbedtls/component.mk b/components/mbedtls/component.mk index 541009de6..6d49cd722 100644 --- a/components/mbedtls/component.mk +++ b/components/mbedtls/component.mk @@ -8,6 +8,20 @@ COMPONENT_SRCDIRS := mbedtls/library port port/$(IDF_TARGET) COMPONENT_OBJEXCLUDE := mbedtls/library/net_sockets.o +ifdef CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 +COMPONENT_OBJEXCLUDE += \ +mbedtls/library/ssl_ciphersuites.o \ +mbedtls/library/ecp.o \ +mbedtls/library/cipher_wrap.o \ +mbedtls/library/oid.o \ +mbedtls/library/ecp_curves.o \ +mbedtls/library/pk_wrap.o \ +mbedtls/library/ecdsa.o \ +mbedtls/library/x509_crt.o \ +mbedtls/library/ssl_tls.o \ +mbedtls/library/ssl_cli.o +endif + COMPONENT_SUBMODULES += mbedtls ifdef CONFIG_MBEDTLS_DYNAMIC_BUFFER From 1ea174cb9d97732ba6f032157db2630078c76813 Mon Sep 17 00:00:00 2001 From: Zhang Jun Hao Date: Fri, 23 Jul 2021 14:38:32 +0800 Subject: [PATCH 22/57] fix(lib): fix smartconfig stop error --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libsmartconfig.a | Bin 157626 -> 156402 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index e9a581b6b..c3603cc7f 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -4,5 +4,5 @@ gwen: pp: 231e0e2 espnow: 231e0e2 - smartconfig: 3.0.0/4d91b289 + smartconfig: 3.0.0/af78f443 phy: 1163.0 diff --git a/components/esp8266/lib/libsmartconfig.a b/components/esp8266/lib/libsmartconfig.a index fe851642022dd8b5edd0731086b876cf0f4c124d..cdadb3a398e749ebe49d0c24e5863c709d4fcb6a 100755 GIT binary patch delta 3830 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 Qjc!Q8`-#t=QH%lq2}b$+2mk;8 From 2c455c9eb522c4ec7f0249defc8764532259cc04 Mon Sep 17 00:00:00 2001 From: Zhang Jun Hao Date: Fri, 23 Jul 2021 14:22:54 +0800 Subject: [PATCH 23/57] fix(wpa_supplicant): fix pmk error --- components/wpa_supplicant/src/ap/ap_config.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/components/wpa_supplicant/src/ap/ap_config.c b/components/wpa_supplicant/src/ap/ap_config.c index 14f73547e..5fc87cd5d 100644 --- a/components/wpa_supplicant/src/ap/ap_config.c +++ b/components/wpa_supplicant/src/ap/ap_config.c @@ -130,14 +130,12 @@ static int hostapd_derive_psk(struct hostapd_ssid *ssid) wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)", (u8 *) ssid->wpa_passphrase, strlen(ssid->wpa_passphrase)); -#ifdef ESP_SUPPLICANT - memcpy(ssid->wpa_psk->psk, esp_wifi_ap_get_prof_pmk_internal(), PMK_LEN); -#else + /* It's too SLOW */ pbkdf2_sha1(ssid->wpa_passphrase, - ssid->ssid, ssid->ssid_len, + (const char *)ssid->ssid, ssid->ssid_len, 4096, ssid->wpa_psk->psk, PMK_LEN); -#endif + wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)", ssid->wpa_psk->psk, PMK_LEN); return 0; From f00bddbf2f64e0e1fc3dd7ce3dff11da03909bac Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 30 Jul 2021 17:59:30 +0800 Subject: [PATCH 24/57] feat(nvs_flash): Update nvs_flash from esp-idf MR !14548. --- .../host_test/fixtures/test_fixtures.hpp | 25 ++++-- .../nvs_page_test/main/nvs_page_test.cpp | 86 ++++++++++++++++--- .../nvs_flash/src/nvs_item_hash_list.cpp | 12 +-- .../nvs_flash/src/nvs_item_hash_list.hpp | 2 +- components/nvs_flash/src/nvs_page.cpp | 15 +++- .../nvs_flash/test_nvs_host/test_nvs.cpp | 5 +- 6 files changed, 115 insertions(+), 30 deletions(-) diff --git a/components/nvs_flash/host_test/fixtures/test_fixtures.hpp b/components/nvs_flash/host_test/fixtures/test_fixtures.hpp index 0baef7d3f..b0915682f 100644 --- a/components/nvs_flash/host_test/fixtures/test_fixtures.hpp +++ b/components/nvs_flash/host_test/fixtures/test_fixtures.hpp @@ -52,7 +52,7 @@ class PartitionMock : public nvs::Partition { esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override { - return esp_partition_read(&partition, src_offset, dst, size); + return esp_partition_read_raw(&partition, src_offset, dst, size); } esp_err_t read(size_t src_offset, void* dst, size_t size) override @@ -62,7 +62,7 @@ class PartitionMock : public nvs::Partition { esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override { - return esp_partition_write(&partition, dst_offset, src, size); + return esp_partition_write_raw(&partition, dst_offset, src, size); } esp_err_t write(size_t dst_offset, const void* src, size_t size) override @@ -122,6 +122,9 @@ struct PartitionMockFixture { const char *partition_name = NVS_DEFAULT_PART_NAME) : part_mock(start_sector * SPI_FLASH_SEC_SIZE, sector_size * SPI_FLASH_SEC_SIZE) { std::fill_n(raw_header, sizeof(raw_header)/sizeof(raw_header[0]), UINT8_MAX); + + // This resets the mocks and prevents meeting accidental expectations from previous tests. + Mockesp_partition_Init(); } ~PartitionMockFixture() { } @@ -151,7 +154,7 @@ struct NVSPageFixture : public PartitionMockFixture { nvs::Page page; }; -struct NVSValidPageFixture : public PartitionMockFixture { +struct NVSValidPageFlashFixture : public PartitionMockFixture { const static uint8_t NS_INDEX = 1; // valid header @@ -164,7 +167,7 @@ struct NVSValidPageFixture : public PartitionMockFixture { uint8_t value_entry [32]; - NVSValidPageFixture(uint32_t start_sector = 0, + NVSValidPageFlashFixture(uint32_t start_sector = 0, uint32_t sector_size = 1, const char *partition_name = NVS_DEFAULT_PART_NAME) : PartitionMockFixture(start_sector, sector_size, partition_name), @@ -173,8 +176,7 @@ struct NVSValidPageFixture : public PartitionMockFixture { ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, value_entry {0x01, 0x01, 0x01, 0xff, 0x3d, 0xf3, 0x99, 0xe5, 't', 'e', 's', 't', '_', 'v', 'a', 'l', - 'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - page() + 'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} { std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0); raw_entry_table[0] = 0xfa; @@ -202,7 +204,15 @@ struct NVSValidPageFixture : public PartitionMockFixture { // read normal entry second time during duplicated entry check esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32); + } +}; +struct NVSValidPageFixture : public NVSValidPageFlashFixture { + NVSValidPageFixture(uint32_t start_sector = 0, + uint32_t sector_size = 1, + const char *partition_name = NVS_DEFAULT_PART_NAME) + : NVSValidPageFlashFixture(start_sector, sector_size, partition_name), page() + { if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page"); } @@ -392,9 +402,6 @@ struct NVSFullPageFixture : public PartitionMockFixture { 'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, page() { - std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0); - raw_entry_table[0] = 0xfa; - // entry_table with all elements deleted except the namespace entry written and the last entry free std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0); raw_entry_table[0] = 0x0a; diff --git a/components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp b/components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp index d3899be78..e5ca9ed08 100644 --- a/components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp +++ b/components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp @@ -1,11 +1,16 @@ -/* Hello World Example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include #include "unity.h" #include "test_fixtures.hpp" @@ -25,6 +30,8 @@ void test_Page_load_reading_header_fails() TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state()); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, page.load(&mock, 0)); + + Mockesp_partition_Verify(); } void test_Page_load_reading_data_fails() @@ -39,6 +46,8 @@ void test_Page_load_reading_data_fails() TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state()); TEST_ASSERT_EQUAL(ESP_FAIL, page.load(&mock, 0)); + + Mockesp_partition_Verify(); } void test_Page_load__uninitialized_page_has_0xfe() @@ -57,6 +66,8 @@ void test_Page_load__uninitialized_page_has_0xfe() TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0)); TEST_ASSERT_EQUAL(Page::PageState::CORRUPT, page.state()); + + Mockesp_partition_Verify(); } void test_Page_load__initialized_corrupt_header() @@ -74,6 +85,60 @@ void test_Page_load__initialized_corrupt_header() TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0)); TEST_ASSERT_EQUAL(Page::PageState::CORRUPT, page.state()); + + Mockesp_partition_Verify(); +} + +void test_Page_load__corrupt_entry_table() +{ + PartitionMockFixture fix; + + // valid header + uint8_t raw_header_valid [32] = {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc}; + + // entry table with one entry + uint8_t raw_entry_table [32]; + + uint8_t ns_entry [32] = {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + uint8_t raw_header[4] = {0xff, 0xff, 0xff, 0xff}; + std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0); + raw_entry_table[0] = 0xfa; + + // read page header + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32); + + // read entry table + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32); + + // read next free entry's header + esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 4); + + // read namespace entry + esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK); + esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32); + + // we expect a raw word write from the partition in order to change the entry bits to erased (0) + esp_partition_write_raw_ExpectAndReturn(&fix.part_mock.partition, 32, nullptr, 4, ESP_OK); + esp_partition_write_raw_IgnoreArg_src(); + + // corrupt entry table as well as crc of corresponding item + raw_entry_table[0] = 0xf6; + + Page page; + + // Page::load() should return ESP_OK, but state has to be corrupt + TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0)); + + TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, page.state()); + TEST_ASSERT_EQUAL(1, page.getUsedEntryCount()); + + Mockesp_partition_Verify(); } void test_Page_load_success() @@ -881,6 +946,7 @@ int main(int argc, char **argv) RUN_TEST(test_Page_load_reading_data_fails); RUN_TEST(test_Page_load__uninitialized_page_has_0xfe); RUN_TEST(test_Page_load__initialized_corrupt_header); + RUN_TEST(test_Page_load__corrupt_entry_table); RUN_TEST(test_Page_load_success); RUN_TEST(test_Page_load_full_page); RUN_TEST(test_Page_load__seq_number_0); @@ -929,6 +995,6 @@ int main(int argc, char **argv) RUN_TEST(test_Page_calcEntries__active_wo_blob); RUN_TEST(test_Page_calcEntries__active_with_blob); RUN_TEST(test_Page_calcEntries__invalid); - UNITY_END(); - return 0; + int failures = UNITY_END(); + return failures; } diff --git a/components/nvs_flash/src/nvs_item_hash_list.cpp b/components/nvs_flash/src/nvs_item_hash_list.cpp index 7e1c1241a..21bf8b315 100644 --- a/components/nvs_flash/src/nvs_item_hash_list.cpp +++ b/components/nvs_flash/src/nvs_item_hash_list.cpp @@ -65,7 +65,7 @@ esp_err_t HashList::insert(const Item& item, size_t index) return ESP_OK; } -void HashList::erase(size_t index, bool itemShouldExist) +bool HashList::erase(size_t index) { for (auto it = mBlockList.begin(); it != mBlockList.end();) { bool haveEntries = false; @@ -81,7 +81,7 @@ void HashList::erase(size_t index, bool itemShouldExist) } if (haveEntries && foundIndex) { /* item was found, and HashListBlock still has some items */ - return; + return true; } } /* no items left in HashListBlock, can remove */ @@ -95,12 +95,12 @@ void HashList::erase(size_t index, bool itemShouldExist) } if (foundIndex) { /* item was found and empty HashListBlock was removed */ - return; + return true; } } - if (itemShouldExist) { - assert(false && "item should have been present in cache"); - } + + // item hasn't been present in cache"); + return false; } size_t HashList::find(size_t start, const Item& item) diff --git a/components/nvs_flash/src/nvs_item_hash_list.hpp b/components/nvs_flash/src/nvs_item_hash_list.hpp index ca21c92c1..e724c4f02 100644 --- a/components/nvs_flash/src/nvs_item_hash_list.hpp +++ b/components/nvs_flash/src/nvs_item_hash_list.hpp @@ -29,7 +29,7 @@ class HashList ~HashList(); esp_err_t insert(const Item& item, size_t index); - void erase(const size_t index, bool itemShouldExist=true); + bool erase(const size_t index); size_t find(size_t start, const Item& item); void clear(); diff --git a/components/nvs_flash/src/nvs_page.cpp b/components/nvs_flash/src/nvs_page.cpp index 600759fe8..0be9960f5 100644 --- a/components/nvs_flash/src/nvs_page.cpp +++ b/components/nvs_flash/src/nvs_page.cpp @@ -393,8 +393,9 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, ui esp_err_t Page::eraseEntryAndSpan(size_t index) { + uint32_t seq_num; + getSeqNumber(seq_num); auto state = mEntryTable.get(index); - assert(state == EntryState::WRITTEN || state == EntryState::EMPTY); size_t span = 1; if (state == EntryState::WRITTEN) { @@ -404,7 +405,7 @@ esp_err_t Page::eraseEntryAndSpan(size_t index) return rc; } if (item.calculateCrc32() != item.crc32) { - mHashList.erase(index, false); + mHashList.erase(index); rc = alterEntryState(index, EntryState::ERASED); --mUsedEntryCount; ++mErasedEntryCount; @@ -601,6 +602,16 @@ esp_err_t Page::mLoadEntryTable() continue; } + if (mEntryTable.get(i) == static_cast(0x1)) { + lastItemIndex = INVALID_ENTRY; + auto err = eraseEntryAndSpan(i); + if (err != ESP_OK) { + mState = PageState::INVALID; + return err; + } + continue; + } + lastItemIndex = i; auto err = readEntry(i, item); diff --git a/components/nvs_flash/test_nvs_host/test_nvs.cpp b/components/nvs_flash/test_nvs_host/test_nvs.cpp index d8467dfe5..b7a2110a2 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs.cpp @@ -313,7 +313,8 @@ TEST_CASE("HashList is cleaned up as soon as items are erased", "[nvs]") INFO("Added " << count << " items, " << hashlist.getBlockCount() << " blocks"); // Remove them in reverse order for (size_t i = count; i > 0; --i) { - hashlist.erase(i - 1, true); + // Make sure that the element existed before it's erased + CHECK(hashlist.erase(i - 1) == true); } CHECK(hashlist.getBlockCount() == 0); // Add again @@ -326,7 +327,7 @@ TEST_CASE("HashList is cleaned up as soon as items are erased", "[nvs]") INFO("Added " << count << " items, " << hashlist.getBlockCount() << " blocks"); // Remove them in the same order for (size_t i = 0; i < count; ++i) { - hashlist.erase(i, true); + CHECK(hashlist.erase(i) == true); } CHECK(hashlist.getBlockCount() == 0); } From f89953c896999a0cc41383bea275422d5fc68649 Mon Sep 17 00:00:00 2001 From: Zhang Jun Hao Date: Mon, 30 Aug 2021 16:25:56 +0800 Subject: [PATCH 25/57] fix(lib): do not rewrite nvs with invalid value and fix ap sta disconnect evt error --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libnet80211.a | Bin 485864 -> 486240 bytes components/esp8266/lib/libnet80211_dbg.a | Bin 537592 -> 538088 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index c3603cc7f..68d1e4540 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,6 +1,6 @@ gwen: core: 231e0e2 - net80211: 231e0e2 + net80211: bde282f pp: 231e0e2 espnow: 231e0e2 diff --git a/components/esp8266/lib/libnet80211.a b/components/esp8266/lib/libnet80211.a index 375abf9858481617da14acdfc5e6d7fc94215525..fc8e727e5868caaed9d12a02c06d393cdde30249 100755 GIT binary patch delta 10358 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 delta 9810 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 N?Y?$T@piMf`cF$^>W2UT diff --git a/components/esp8266/lib/libnet80211_dbg.a b/components/esp8266/lib/libnet80211_dbg.a index f33aee19bd1da4c88209f0d676b9d125ac0a569f..71b7ddbdd82644c956912e43f849a4af9f66d91b 100755 GIT binary patch delta 14552 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 delta 14103 zcmche3wRVoy7#*}Gn0_agb-p9xj8cgGLaB6A&`K8Bwz@NT*AemfPkR5vMR^{j=&Bo zX5BsBgO;nH;Uc0NG#Us31bgN6>D{~cn|_}j@@nGnFW>d3_1gc_?(3)N z|F^wgrlyDZVeLbXXu5qLu}Ra%R{gU5!@-*V3--{@8Ao-f)&A+8H9?E|@9&{YoxHI` zi?a5&c56}p;@#0RRI539{tNe=@cnapbE@Xx9-qR%hiL%*!k-zRI%|IgjEtV#Q?d+6uj{~`3Y8&)h8BZ#fH4uXMN`*iFHQ`b*aPXg2YoG(032xvQv^rfGR;-rAlOIh}Ks-RGX>Z(Jxoy4bNc(<}BEH9cn5)+tS+P8OUG zCf0d9En0N>nct?A*DiNfkN=%7Mtobn;HlX{bS?k-=`Nysc~W_QadmY``TMbANO|gu zoy3UpJbadvk9)D#mACYd7u)F7w6`9sFKatEoz)lC-|Y~A>Y0DKDq4EJak$0w^2zU} zjPk;bANxA&PNm;M8LxCLN*#L)_AS`cRQ-f1+4m&&*4U}Ple1#=_T~4~yQ^E*we)F| zt7T2S@4l=l_uhKvw6wh5c{$Yy|Jc{Y6@ck3t>#O&c>U^7H&l`maU@UY0ZZELv2rth@r**3k{rXNw7 zi7Qu{2~EW=;sic5?Ro5+BpG#_;vF>k=X?P2teB!hf?Q3o>7kR?NJYZWG2i8H}eH8S#q8XCki$$R`V*g%wX&Y!it5@;A?lA)d}Asv_zv z_dYACJ2n(&g2E zKnMY|c`#9+=Jr2`XyM5)S!o-v40-?aFuU4BONp+Q8=gm`ylSwWBTaURMBU|sL|GS>~BL_K90QLc$9h;ro?qFyFyCh8@_M7>RviZe{~mVI9oojrLb zDkjR4zaq*v(R`wO`8-h{6RjocBexOtHBl2$U-<*kH71I|*($D)SHA?*&qVn|{p8Ir zA&CAannToIKKl|9%_RxjR-ys&OLn~0MCXaFmF+6T6P|%4T8cAY43rxxV8yitTRl;M zJW(O;@)Vk=A65ZTC?~Bz$3Z4)A{r!rSRt53cWfmg(K&u|kxic41vm#?oy z7$Z!yk7$HEN5lmhTL&-DNIBqDpiu_VrV)*jWv?QN5))MrmB=l$8f~JJM5ATwYY1$N ziBho)h%vG+(O44|6OEO>dJVqDnP>^oIJt)CCKJ^X-6W5(W2uQ+h)QMRA8}yEn`j1> z6fs`@{*SP_*+kC~-7No1#2X8?twguTFaL{W}RSU${RvfR&Nr0h~B=3x*d#VaFZ?jZ$aZQ`PdfGO?+2gFtV*|+#(WO z_x?%Ks)RhYMfjawtn$&)_pWFwJG>_nbnn|T>pjuc8Nj+eR2DRfB>C(2L~DKFCixrk zIpB-ssHCX2aue;(Zjw96&tmQFYx;55gZHbIo$A4}vFtu<3_XE(%zN@~;*G$$(pLrd z>+0ctWWC%>ehNGy_v`?_K)$+O#=lRFHF%KWX4w01v!p>zBF@HgI@Q3-fRUVa?~8Qj zQqV1CjHhV5=>r+2bt%@Wo`!Y52H?`|a(DyqqZjd`#2dHE7l~^x;%4I1M)@`ISz`I- zn~1Rc2Z(Tfqa5%7cmONab7le-egONXM)^2-E!HN#F=!*Pdzbu__&9KHSx^l(9k;^G zm|Ze!D|iPiQV!G2%&oAm-6elR&Xwv3lW!vLut)ABufhUSVz_sI2z>88+37=I2X6Qd z15W@(Vt)OhNY~T$%V*Jwd+a-`_S-K{(0DKwoNEo^v~BQF`myZ24OUC!#BH#u{8*Nu z>O6@Br`WKnr&ZvfJV2{#d4X1?2W8jou-bFww}r&%U9imrOSR}Ns=_^G@drL);m zVU;R>y%Sb5kIH9Jbrxei@yIg=ak%#H#I$OU$`jxx|lPMS8}}9C5hw{J4$B)9((#2y;ko*uf-?j24E}(hxee@)|1k; z7goFRAoTBs)!@Cb%KS=>1BTV2y|6m}m0UxsY&-~=C)06QIdd;o-5+5x`Lg3jFs?l< zi#~$!9JDTxQ+6RE4}T3a~oU|VS556F~?niTNt{l$t)CD;grSmw< z=9oF7S%IC0ajNh582z6_{X5z%gI$u* zKeq{X>%oUKfmeZlD);<}32YLrqZ-j5(SR`DX+oHf2zjCjVbskoRGqu~ zSP5HCtC>#OK&u#enpSI_GWigyqh$X>SawJC#htGFfl+Pc!b3POM#;xW$AFqAPa|om zJWN`8(Y8Y~PAOI$=AwFCvuJH=o_Vp^n8Q-5dW{@ahkMp0)J3`6(Ts4m_m$_GF>|j= zb~=pUSM}GlCOP!5=2vS9jE&r;XN|gyWmiTCT`un!)#j3hl$sqKqZVDtl51x4h3Fvvp^rCg5pfVDyjJW+`OQcrQT(1f(u%~dfmQxWC?~=InqiZ4=b>6++fO|t> zQShaRdr2TF-OEWMyb1fAG3!Y}^W76Etm_)k`{RWe zrX!ZH;jj$XN3{!$5;>ic(pTxO5yGvPWof?KBI(OB49`W^3*Wei`yn`fNOuhpGwKQ^ zM1o@?6XW6h9{Ok~5Qb&LwZb>d3ZbkYEk{R!LnDhkhV692wl}8Y8xm=0nG?_#j}S&E z14G3@yd;}s1f*{&;c@8b>tp2X3V0b53Fb#W5$+Vj&sdrjt{f5U5ee*B_@gLc-PHq! zb>}yQnmaMyeQuEM$`HW}#F8JCw?uE~BJy`G@=T4=7T+!=&j`BkCFV>Z;!ezIorDxN z-W19|nw|boB?e|H+X!DfYZ^uIqTs4XFqN6?V+@4r+n0(=rvH@5Tr=?Iy@8!MB0Z;2 z^NaNS7xPx?4PlLWt=7wa)Lf%9U;Iy5J+Jx1#jJ+@u3?&SkzgcjOwmV&4S&--cTTBB|ElO*Dh5oNZ?FM3`qFvw1cg{348OMjJ!5 zqFJbL^~y)4F@g4n)xT?eN8ubgkxlJ#3w%FEd9Q!@){3oBQaq;U$&L<(hA` z6;s*sw0t8R3a+ryxy>+Ms`)CA&a*$I^L;ZgE1l&R)44Jne46P@H`2L@W`!$XagAp- zOEhE^fj$xbrc;|7-AvQ>57-hl)i}hVh6S20bTO*=TES!C;38z|-_M9wjert0-@4p0fP$2yQ5B@4MNUXIo_Hu5hpv^E77p2+aytZg+Vj z`Fs3X?v@c=v4pHFS<~|O1a{uoT0FqIE7lCjH3S#EHNS>IT8YnHP#QjRw>LP5=R;^7 zjgxnL%R#U7^*4i$YF#ig9K6PeT--~G;=0V)?FSF7JGL`7JxO;x6&809i(lD3?=-ae zIm6KA=N;6(ZkSJwzAUb1cJ`bNJ)JofdQRaozZ||TDlz2i9QNx;m40yxP4nFw2Bij5 z!ngo#ODM<;2b06z5-)-s!`5KyFzzBNe-I_Cx!o>&DaG1+esgk8O&KnGQFO9VeqcdQHp0kTRsb*`99N+{SIiW?+oaHU?@V`T6}V& zQ|fG#e(X&)PR$pTL=KF^lJ+j>v5MaUZ4EF1n)ZI|kJ$L{pp%sSa_FuY-!OX5W>gQI zuZ(_#=ElLOt>7{p1~xdg6G`P0nY z(0HUYoEAY_nJ9*~f}0P`jX_ge!L7D&Y6cgggA=v}YIgKv{~FpFpamM=rVZ|PX<9(( zTxf3WL+wS$K4YNimVUJ!8zDh zHhbzD6z?6aX*a39k3p9x{Ta0B2jd?>B~CSbb+G}zj@kHkHh$j5qY$|jkOSJS{3LKj z*jP|AK29tdngNri;v>10YRHNyf1rO?d1z=bhvJpaO9MNBl zhVGy=on|Oar@1!!K}rvUO_9xhtj(SamlecZQ-_Sf7ORGl==_k<984U1LRE&zS<#M^5Zk$mT4QdpY+>4{^cd(} zO4Ik}N;6SkDg6>+HeHpT0i9v9nWr?5ZUr^3NT#b=HL&yBO3#GetTYE`R2q}ink|mXNu{|Y zoK@PmgQJbX@$fP;)EvvBG;ckv+N#PJxxba;8oX9*6YEGpkrC^-A@sOfN}EtVXVVMe zMR0Y(wpVd7>Nv#@E6%5|V@m&s@~<|%7=0{1=M*QSh94XpY)-WT#-WT+nwJ>sM($C@ zE6qi#jnZ7=J1UK}U-K%>voufX0+iP(&1HR%(!3=U>G-{r18}(=sTz2H7_Bt<5(H?? zV3OiwljOQMTwU`NdIX3%ZZZTmKCjR~=qGHPqAWwe=s51v3J%7~CUjt$tR zE6)4h45j&uGh6BTDF4mImnzK%?iZBieeNZtd5>JFG;ddx&>_x}H_SI|4HX#NIs|`K zoQ&Fg&OmuX zj#ip8XrpurOB-K{K&%OLR-BC5nn0Gpk$>K`gUX0buTi=HGk9EaGHPqERf_XTV2#o|KdO}8fU?@g zo0aBQp3jvI@oxSXRpFz+mrC=ldsgWmP=06Q8*Rbq>W)fAZ3VZ9Hn-seTYF_gMjfYk zXD5z7XU|869A%V`vX{~f;u@v-bT+`oZ%~?FyhbX`$BxlTv+qQuZ$mlR#%mFXnOz){ zdsG7T^7l4gFW*dXv<=n6%?rSmo2?vc7(TF7D|0gHIK|&q zoZkuGRr(0Z4{W*-eXKL$pyFiI)>u*2;|jkx#;PX*KDNXw&1arAO7n)>UTHr6bh7c? zw!yk7PDX7FwvRT`@PVyZ+3e$j#!8%OC{YdkHhPQFd|sNQG=rF-G@qUBvhgN3wq|_4 z;$+lT5Y4nvf0ZI>GZLp0AuDmJVTJ0_X{d%7%>EvN^3dAJJNr=5_jm(i%>x3pRd=K2<33Xu}l}(g<0xCeCL* zUOHpY@k*unOxW3`TWpT96(^&%{1hlY1m$3*`HJc+`$bpYmQ#wNNqDV$@E_VER?Ra>5VpBPt7-w*mm1=vrV5gwA|J3bg`l3)k!f!l2XlX%ZS>UdTq_bfMbC}U)oO|%yjV2jxxGC@K;Fv z<^A0q!}a6+d+F!dU0A Date: Tue, 31 Aug 2021 16:55:17 +0800 Subject: [PATCH 26/57] feat(phy): update phy library from 1163.0 to 1166.0 1. Optimize RX blocking certification 2. Reduce TX power when bringing up 3. Fix crash when waking up from sleep in case of using 40MHz XTAL --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libphy.a | Bin 265092 -> 264160 bytes components/esp8266/lib/librtc.a | Bin 5056 -> 5048 bytes .../components/rf_test/lib/librftest.a | Bin 60570 -> 62302 bytes 4 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index c3603cc7f..07370d934 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -5,4 +5,4 @@ gwen: espnow: 231e0e2 smartconfig: 3.0.0/af78f443 - phy: 1163.0 + phy: 1166.0 diff --git a/components/esp8266/lib/libphy.a b/components/esp8266/lib/libphy.a index 3113a722c9d2126c49bba00097b44a85e1651c38..df1c4411d7b3b0016429504f0b20d417ae7c1813 100755 GIT binary patch delta 49650 zcmce<3wTu3_5XeLnFIqfKr##v?vo)(&;XebASh@O5Q8E&QKOH<*dNsd5mBR}r50OMP^#Ec1#2x{>b&3YKIQ4N>oj?1Fi1q(LO#FZ0 z^f;e^pJ!XGF}d6d92XOQ#sAN8H?K9{qLpoN^P==W2c3uGc64(x>+g2*!YZ+VimxR99S6dkw5+&vu&Pb|m?EuZxpqz5md63Qa?Aq&QZ0=wATwhg_{QcrdYEAOQ#3Z#pc|AU}lds})QL<|t^|SH0 zG5I_`tCQ(VCaGn~^YOVZ`6xbHlK;SGZSu^elhn%OFYviO`Dc9YPY%0vk~)^W4WF6G z-{UhcdE&B3sw88yxJ8|ud}u}PabwxjDT$~&wQh6PojHBgFz4m5>b&Gf2QxR{ zyP?cZj6?4^nrjtDt*cc5<|v+y(F$ALtt&(xr1N`Niy>ztX6XE0)+%s5;x$_CWBn5B z1^V3}0a$^xr}Ii^i-yqFAgIG3yJ+QN-5}!5daYm(!4-l+B_n|E@&vtFB| zW+kiexh(nIYpyoT^J?ps9>%Mu#>yd0VoWnNJ$vjhq zomImFnaSZ#6gUsY1Dl)|`q-Jy`+e+aa?XV%&P#=X`psW{I;7w@C*9JA#)l4<34f#OQXRuAynMhFMJ+R$i!g*O{@CLdyypRIH(@sU0=vQNq26hHal(st{PlBdtq(i;CS%}=Rle2>vSH2 zY6g!{?VW{Xs=IRzX~Y=S)u|qX^3%ttOy|cjs*`j77*&S)J{+U^I3319v3v{$__aZS zPEPh%)knn}hmTdywCgtti^B_CRc9YBJ0BMZauV~7S6T~v@-04jxldjLc{-fGi5Rwu zt;ZpAsV~v;sn%~G<9`eLhLvS~o!SMV2)qJA9kxa#tPh!sz$DA6wEl9OJk$DKWKK<% zRb{0CCWF6)K5Ug(+02l@UJmrhr-|(PzuY?Kxcr1=U2>elvgSda07u6V!&aGfvoC+8 zPhRVjpYh3Cee!Fj96=?2G8K>yC7Ta*NrXU^h+%82)fuD5K`qttIBNi8_Lcik*ebV% zL1u9KILkU4atY+0=`lLnnkM;Op$nsPvmj@H`|JFP){T(ILjFnTPquCgSP88tN7KUA zRLhY9pJ;<=)+6E&qHf5qAy6u{5SnQh)EQb~S!?mHND!Q*f(Fa}F+56VyH@eyf_~?51Mbtxz0s z-i1Q#adMU+$#bq{vc_pScRp$)69a3-SCMKJl*O?SKJ?=nK z;ml)F@4Uz)*J-~T$qwftCgsi(Oj?}pm_(iNE0E+m_c0mee8FU_GxAO(`$JNL@giOi4*i%NBtbh9%mqv_0AL~KRP!dNl)uzSy$^4TYs)H?a0N>8$VYk zsaoeKjf$NfE46JY61!X9HFn-b?;7^qvF@0ip(Ijdkk24}LH zlT%joS53~fR5Xml%7UVcvuTw&{>0ENy|{Q-agn}6>0+IN)q;uVcEIH@NS)l+?`}1q zU5^uIMZNz!So5pg%dk_SbI$&S%IP)i)M4>c<3(2K^;bmWBcp`{g>h@doMFYohRtle z{TJ#bg;m=)#!>OKVO*XOoT0m;BhlQv{DPvA%2{)3Y8Ng_v(wYl5d-PzY4~4y$TRI< zoSgNlN20!iJ1k_SaS2?W$hyRrPo)ecnAc zJ*2)$HCfj3dqSOp%YWJFU!9g#1@F&~+1CEawRJHS&5IBCRo|sK!8@MF?sZ>%eeM1E zOKq!exvEPQruq=h64uXbs%|=<{z%`MvHIojuFlDv z8P2%Bc=w#FvVgVlKxO4O6-VpFX5DA%efdKhm+OWtzsGIY)POZGC+DTq>MFIg%G!T=l=Z)i3Wr&!Yx4osh!hnP{-tf2f8#yf2qz% zPkeXu=#kX+s&LMc)UM8URhRdwvOcNGjJ9N6(9-qY!>PQEu~=S{ZRK?=j1|NhR8zn@ z@OdiM*NR5BsK2lta41sPoT&~`qFuYD{3z`{O67c<3iX(}+RFJTwV+{Ep>5^tNzLzk zGKV~rhMwK05*YN=RT=K!tzB}#$`kTBp4c&bN$jEGfvT`MJi&fFYe93D>FuUA^s65qRWIqr zSEw%Wt*O}dez3*p&F_RphSDe4pNbDfd(MQXRPXei?JV`YbInt#+o_H1j;1P9&SRfJR^~0~HZ#3+T`KnM-l=P>(didHtVY{T(^G2ffN{!- zJ+mk_y?b%ToI2h1jM1Asv`SAL{WkT*lJ?KN{?G^aELu}GNtI2q>poG7)|X8R?9YqWjZvR1uy>wog?=}n zf4|UqvF+cFSL#cSce#pf|1OFHBriTEJYZ*kj0W?6LjLDw{`Q9NVKO>2Cv5M`u}aG0 zb8h}ER#~Agj@_PRh4u_se?q$xEYv(YR5w)B zO;82JUZF8f=tH}7OZ3h)f~^u~;zv^(`8oxKq&eJ&M^)?(Z$(oP-}f0jbQu*}L> zRzWNZ?ZC90r<@Mm0{!~$#HNcrqKPM=lTE3eEvby>c0IKBobo!t)^(>nSY1!zsLFu=*gRcvgrt4hD>WS7|+CD~UTqnyaeC0>% z!{7EF60@BdTU5L7xWA^Xn4MetKT|6&Jq>q?reEM zZ5$GAJ`yV1US-==0rfpy#{Zd$1+2FMEoJJTxy`k=(h4#2Jt?eDhjT_VWW0OiM^`29|U40yS z_xTj|gCj$txZ!BL`NO|RZlWm=(4ZO?UUm@dZ#4U)w zMP%54^i3z{UA11VYTWs*ddW`j0Cmq~bAGQx_=B7evOZ8{dz9Kw!<;{)j_yqr z+7t3R7Zjx7X7CSP28`}FwPA1X+*renyh-eQ?_27`NxM>^a1$rao2SB%HGS%cUvtg0 zoIYVDlF}w@b#*W*PP22mM2BX^Le_gZS=gDk=Y&7W$vk!xc>~kJ&67JGY25mnDpHB~ z=2XsR9y8?uOkn%?>uB5;3RRRoL+!wT_Lj3T6&=deF*2?6$yEHQ)`JYLX_Xe=kiuR} z13UhB3Y)QukBXL!<^ee{fZe(D5#|=#g%8y?C0K$|TF$RfMP|-}sVNQIj^n?i(ZDo( zV5vTU#VO_Q*M-x|Yztj2+i?_y3W{{o(x}bS0=E|KK>=Y87UcxI0xK=eAVgvrW|7q51IKy9*sJ(T>@8 zI8LNOgA0b~W~9XzrAmLs%!)wC`I)7+q)N_Y#&`~8MWA$HirO2gopNJ>b~>j#J$`+P z&8}s$p&gk%<$_dPpL*Q>)U;;Ar?Oaipsb-z7cads6&eHLzUQ`q*>-%kc8E_jcUEh2 zG1fEnSmQGx^H*A#%BiG9aT;ggGEM=cfoY|ergAQA%ebU1#wl;9&8kla^)xefDhv118@0`~A$wQV z-YMbcXyZTjs7Dnxy9eG^&1q_18biVo+cc??23}iU}+^_PoMxh3VB36Y^(-=LVHl!u%ri7e^pVSG-ev?Cq zGGuVKor#E>7%PT&lfm_1=2O2Kafa|wqzpV|lZPVGCKr|QQ39C{h**|3r-Q?ypA7Ei za=@CSk_Y~HQsbwesUmyuMzJV|MUC)QaF+1v;4Z@ZR5ItozKxfEp$^&|y=oKg9*&f5o&#r!O|!x88hilkjn*+R1O1SDAVu%HSy}Xk zzzp&Pr1rf>RKMi2=Z2i${Y{nY8JI*h;x&@e{8~g_LBfx<2GJY2$H26u%?3oTUyWck zgZiz8{xvWI_2dFXmj5Rr1M~?k(14Yts70Vm=H)00q`|v4t-Xy7ldnKN%iaoR7RxRJ zc#TU^i9kJ>dis1=>z(HZ1Y(UtzEU-If?8S)Lk_<&pw|T0(=P$z+EVLTLqFk1!1!O6 zT@Q$eo=eBmzXXo2ZwSUG_y2J~1{ol5p#F0=9g-qIdP zrE~Z@^#B*B&K?0(ym8I<>dio_t_*oyoHd&QL)f-Z*Bi0# zze>Z2UF=t?s?pT85U{Rp z6F>pI8?~td)`B)c=hyn=8+`IYr(aQ^Ut*C@z1Sz$`Q)WOd6`eX-6t>i$#)(vC#;pn zEA&@IZK{C9{k|;(^qz0Z+>P2oz`D0h00peIKKcIRxVW0 z6tMo~lfA9gRR=7EgQP74tbp@*wmrj{(+^)=-Oi62qWtJ#mpt<2r*`to1JTCMdf7Dr zXIu~HFMtKU9=oES-Orgr#l8LP{mu)d+oN{W&QrhGpB8CsiP~2xTqcZ&**S?TjT(7| zy9sg>={TfeJYVPin-`eB8Zr<4YY@XYBDl3OFv+sIs}}&=L?&WS4&w-UTk>hc@}EFv zdOc#;T9B}g_zeCf2B&L-T7A>V0^C!>)(sXn6l^utEJS{}<9+wSeI*OuF7W1(!Ig7V zxyaPf&veMV3Ti+-VXMnRYp&1W7U#goK$isV8Cd3*K9gsC^2IU3t{S7i3$1-f-caV$0Cqfy~kU0|W96xSV`RuRr$x9)lP13={*Qq2F zY>};};0f#3kU1rfB8IJ}tnH9_sB@PMTTff>L-qnIJ`9=V-6Q!~>wCzoz+HsTSzYm% ziuvx5z1ccN4 zaYWA2Ble2bmzP!&*pN8nBBW<&`&X?JU;g=!X?Gzn!Na&Zzfug`3OlKrA+z_h5yRH& zR{e4LS?V!ykf-zCv>G9EgxsUxEo&EK4!Ju8?^u6?%n^0%-?cu6%#gqaF$X;N>ldgS2FO)FuqaT8Thg~*W5XL3RX2`rC=bjzLB}p^n z8szhyHjE4XKS1^Z9e(7KkND(&`Q#8Er+VifI_RqvRJucZnok}NnLRE?4C4}L3gley z8ZG}|&GgwX5E<>oh;&m+Ae$p}59A*?|K~s(#x>KUJ_nn9@(!Q;dy(A=I;w-d{BM17 zyC5o)zz#C1YEQ`Qh)ffAoQ!6(mv%n_N37{*0jwdA`E?4TC=>{kWx zvp6rX0gw6&w)x~eKKV0|-3l_*_l+a-?W^6NHaL$Dvh&)_pFRKbnwuKm9%SDYaOTJD z{*Cw@;@ZH!{SBfsd$^tF{}E#Lg3D)Ij$0)DhLC_?EM7Bb4t}ZV)D5#QZp2R%`z!bN ziOnPIdmAf??NLEzeZ8IK+?B9H`llx7SRP`8n*qX?h~#gPhR|{{*9CvkM&^;rJ5n+q z7jd6ZU*iLT7cSIOM-Gafvqt@Dq`dv|II%*6dZc#=--MK-t^SA)gms84KpinmcnEhEJ%tqWN90l_mC)!_x&Gpy9+mOyd9`)BEy~^c; z7Os|zdKd+yL0L%03Xez1t8x~uM0&aKJfw4ke?rQqkhD2~v{v|!NI5}@M+Cy{qNnb5 zg&is=8R^o}AkqwBUZivq=IC@Wm`9!B;f63k^wg1qqJLcU&m%n~{5PaO2wMpZ(PfBi zHGkYyCA=O6oPYH`-OF<0I3vUmBVbNJnealS=LoZ0g)kC*8R6OUj*(n~v=H%J3TFaF zBa*p(^`3AHfWSQJsUrtPKUeguc!6-Gv!dMYmFQ0~%WeNyVHSrMD-y;B0v}?L*#}-n zk=gD7VcJI#)lc|9;4)MPHM&Q?JOtp9R5$>lNaQ(Pv`duv(k0K*+|z5vyo4;eimTh<34f}e1^e#dlCI6(X-+vVOCIq z$g+IYnhRF=kKtxS>Zv0KMV|*&eDuMS?s7yLQArNUGm(6-vRy|z#D+R@Q1mULXCpZs zibo{Ea3u6e9XTlaBFHMuwYdOEf<{zQ2ucR8tElI<*|QAh5$x#~3ok>uM3}?;8)1G& zQOwHH0SK>%o;q^S)h8@oncxqA^qie2%z4s7l;IYRLiQFH^VCK7K;Y1GtrQ~F3+e>d zo@>EdXc^>#_&`WQRK^o2^#jKrVG3dd&%$ZI^+smF*}_OHeg1@=&VMC(R=Qc3jroT# z*KdS9hCLgcFU&=Ek#H2;oDd-w0>4^e0rs5p?9KhHVCtzOdvmYnTZZ>;v7wGE!>hj@ zVcF-P<20)ds086DMCub%QV2@M3zG32QqGkMx&>YmJ$2-u=wB24+ell4S#}hnSN3WR=Habcs0buqQ4XA z1HwqGhlRPaxC&X8D{d-V0A`KTh1n8)3KpM zLmk<(Sqo-a`u?*p8^(Qr`X|7pE_c_h)N2_djc^ov1tRT#hV(Y!HAq(( ze2?&Kl+$|{?6*SqYgeDp!t-LpQ^IeB+3Ht>4w`#r zG18duIHaQu9;5PHBUa2_vj904j?`c9fpDGHJEu>a$GW^NRJ7#t@`kR5xV1c7EGu5 zEC6O7O4tuD8=;SRFu#9aD0=4qOqdnlAvd;AY!UUpk{ z+o~&yFKc8!J)SnFbA&)cKD?{z3DvKP)EC<=;wl|=WWFG!Uael6h4M@&_)rS zL%L148EK2~yGZv5A8?*K&yJ4f-h(g}F#_iBO&7ifDI@h98V-qfb2?b-oleuxYh<&v z97)A>fp9t^i&01RuFR*2z7i>eccpS7IKr(Gp&F5#Li&jCOGvjEyhHdMr200M1vtDv zN(N`82YU*A9H}09F#C6o=-DR@F>TnlI^iVJdSRaL$05>Y0#dz&gO?$HqN{gr6Ls%D zfCixgkp-wDdyfp}iGB@JMDG#9LeW!4_U!dm20ygdTN#)gbHsiF(hd5W9vNF9G)o58 zTQ;Is0XGvih&r-Y!FQtPBIJ?g*$;r0guq zllAln>nRa_9(lBBM*6le2jWX%4g@bhX~TgyNq8jEQw&b%O%p~Oq01zr2I&f6j>?n5 z9F?8IA0U0x;QhiJt#5_fV<7sz5!NHUTzCo6d>ATT^dazU z%>vYsgQBM$_3SaH+p}LOdg{oYeUV|q5lgTzl@vT9y%mVlP2z~>sm;Qy>}BCyNVgmM zC@bJbgur=LC%VkFqjFv58d3c0RL5rYIlHfG(rHBzQ3see+kX|kv zK{{WU71RjxpwXKx%CZr+i$03&U^?@9#0tG0u_4Fz z$hqKByMJ^5^a#9{i-6gWQepPvTxZEl{Ah&Dy;#)rs`mt#v$KVvE(W6NhT6lke&R`)Lv7O|g=s7--lktI|H!m=4)*yQN z46w>~{pcY(*;zaTo60fh5%i4&igBdK-iCPq`Kcc z!y?cH?WrRNMc-Gi5AIqBry|mbI&!eUIlU4C#Vbk#mW||V)Iatlv;Jz)b34-86ZDI~ zeNc=x+yq7ommxhY%r8BLN!ch;eZ2^K4yqnxFnuQK@IgnFNLLFlN6JB?el60T;xvl% zRAF9F{7Lu-(vJ-O+~DtpdGo~JoqR@tBZKsI>i$+2f*u8ZDFtTl&v%XVa;Ok~2jly|I8-+2D)(+tUq;CipjRgE&gkq#;2~S5lQ+OfLTZHS8GDZeDw_k1#Nel)f zlpsdHY?nR^!EDz!(X;Kk81$K7-48JPt@{Dypy_^qIZ*o%=`)J-Q(^Xx{ZhjeKCyiC zvW5|rdRa@x1CUvGKTaO=>SS{_RXVMH>m zy9(1AmI3t6#MwBae*h!s-GZk81nn5iVjPGFn8k2@(ae0k{X@S1thaw~HJD}ijD{Ux z@SfN3`ZF>@t1KqubC6yKDI<;OP&W?DDdUh+e?HO+h3k;Af!_$3AxEARR z!po4}F1!Zmy~68}J|_HYq+5h{Al)mxAE`d-QSo8$SE4`0D>5!|wx~TC$VlcHsk6a6 z$x_cA77KG~xwWWK00fQzZKxv$M>)^T#lvJdglOU|AAQ(x>Jg?QM!;MFcM3m+^cmsz zk$xe}c4x2}*mITe0+h_3-EqtC_?N=tp-=op1m5~jM5Gay)mU*l8L3{+V_}F;jz}Bo z$U)KT!v^}hpu1aaS_d3@4lHNhJIwy*+Bombv%7Jf+i;(fa`TX;OS^a<+{NH-!fZUB z>aZ;%k@gkl3e@uf{ZO#JlLFJ8Q$hO%q!WbswMySfBG4$?Xk?AnJ4>&$`;SLC&fRLL zyazi^OEKOmY!ar6CgGh(UorH%G&^5jiAN_Ropx7Y`r$PfUPqyn=QWQF7za}X{uK#Z zOdUBWdd?8O7}p_#%yl5a+cml2MfibmCL)>3Xpu0>C4M0S9j-T6f5#vNir8#$1ycT< z4Vm^Ah&^>T30ET3%Y{1xfp(tj%Ar8uLZc0JMhM<~>yz|p zu5JR72$;5c&vqNF8~1}d zyv*|&mk*ANqQ*TFlVO{1S0)6uXgVS@=y0wuE5aFD>-8!Idp{RAL-brXWbgazb49-x zsa``ea=J6{Po3_}nS3IF&>K;4H$j+*$VN~{4vIbs_U_#lf@wn?*}E^(L(QE9!5axJ z;6s(T`YzzeXjj`yw-f@6^@R$UPV|sUtMwHD^wg2PDbtn7Rfeu?f^+pXxM(@ub=MiD z5imm(k<23OJefKM@4}-SIKojx(C&DSM&JZcPaQcZ`gYWp-~(X*BDo_{{)K_1rnrS! zVWbov2-*>t`MT{VxHio5mWj40qegyE1g3oqF#={eJvL{#W%ET(9XWWGY$;)8jBzi# zqryns3vuXqu;hupgel`#d?0j3B(vfo;ns?eL4hzBkv6QD?5%)I9@5@2nJGr>71=YQ zvj`V6f<9`&tSkqSdfd#rKc@ocf|(Z?hYtjnRosaYs8=E1D58Gds>oS1kxMEtjn6}* zo=yscxy~89DbSUbyE5MP| zk<7+T621{>l`tLF3bUe9gn2#2UaCu7|GH!FLmfGIscb0`!)O|ql~G3yN?{&~>Ri{+ z&0<3xIVgHvnRG_?Shf+}W9hw~CY~Y~IRC236?%aq>?#6xb}|=YkuVGD>42WjImEP~ z^XbBDfZm#**X1CqO4q+073kS9au9mf?>+)T2Ip1ZXo2Za_eK^}2(s#c4+PyCoHiJA zZ)Am2_I`_%2aeDofjFqAd%sBDPTRIuap5n1&ToEZpEY`-*0|dOn04~p8v(P5`?MbDAuGXP zwD!E5{DZTdRzEmjGwJ5U684SWoxwlohD#LTCqy!v5I|?hY(hI>Hi7#A^=yj16$7)U z9Chm1fa`>NgSlR*kAn5j1i-n}KOz}<5FQiG2X7ZH0KX;7IrvbR3+j+?G5Aa267YAz zW5FlbZpE~Z2y-+}bUC4ismL(W-$J5woSRjmp9bciA+iS*;Kziy*qVgt^zXuz;0^)T zo;HJpXMy>uM*5ixt_q;r6sjTAASzy-A$)~MJ$2;ZT<7#9xSpTnT(AV+flhL6c9RF) zWV@Su<|ZAMYLmfB?e0C`;|aK|hY#=P0k7%NaV~SMmLj3mT3CF79PgLxe|4>1f)iBt zzH9uwoAkZa^_+(8ZZJIe)7^I_-m2?gfP|hm!J-5?p67F2t7qV3G_toK`#dB2DxHme z5otnrInu30MUK`x_A*`3Nk|g#)C7y)AjhldRVn=h(j7)=z5-zWM%BRwR1 z6e%O^(=c{E0$zPp33a$)|K zdyi2MU*;K^#H(wZ|I|l-i;n*?|DHsSvJpzFw13Cj!0xR~IvigRfa>vN0 zE(jMOM!+m`kuaTC3e(4YVfy}+FdMesW&DH_@LS1X>zjn5NLeQQ zi_Kc3`H0@1xLhH6>d4-oxD*&RH}I@Pr&Qix7!}dzC_WJGMx+gOF4=n}_fNCP2l0V00nwX3eGkry4+MP= z4o(B}Dj@>quqXBIeO#C$w@sKMq|X$vABFneuc9H8BSZhp0$c*#D+R`aKNV)rQ^J$MHjii6PXl)p zt^n&l-hiHKBP#kz@F~Kxz;Vr(|G5xKC4*18E)cGUUTez@y z;G}RJ_z~e{U~Xu%Sq|o3!;@Enx9R;7LOq1-lCcK-mN18RxA0mpUqsBp>%gB0bEv-+ zZUA@W{sEiyU~X*W4Pd>ofj5Fr5`AJ5gnSXUfcdBLEU*=Ps_-`OnZixr$-+Cp=Lzou z>pyQn*%t6T(eDOV3-1B*J;wCE7yL8+-9Cj92zN@xK5)J8e(*1a4}$qlW7;1AKO=k? z{G9L+aI^3?;J1X2fjJ7>;4EQ%;Ut_1{XpReIA1s$JW80) z1*Ql`!Ha}>nCr_HbYLu|i<_8Aa92QhO&UQZ+536UQYri}(tH-U(zV|xdg{nQ(etsU zcMq~fY^Wo9w->pn&)aVjQ3^OoM3D9-b9@l85xos3lPo8akTCqY=Zp6N2sMZi-bW(T zA(Clxn{Wow*M#Zs4VM#oSNelwun}JivjJ=i9r2o$!%Ai&2MR~QeC$9ydv%_09{393 zd~l;MH=Y8>it~c7Uhn@XOyzpSpkx$*)qK~e8O#c(BL_uaOdI|T1>qe;+E7OhivB~< zbCHfhRM)unAB!F@SGVw2+bAFzC191p2LcPxX^C)9^v6W6;A<>c$wLo)hpcK`J85XC>dkG)bk`Vfd%&B1A+dir;Z#H{bb1MDku>2i3c{+ zk%OY223fHs2sa?1ALtTV2uel;jjnZ#7Ksscc~OSS3*{& zxi&1rim4+9PviL)VHTp|-4DW}VniJ|DEenazYXbJ<)WIpvTQ_an4l) zmwp>yNe@k)Ntx5`+*+AU3a-@ZUgosn;abOe7On(ajKhrfn*;qBt@LeE$l&dssL)+j;nI`zri{Af4(l=fjg^$;&vuQ+!bmM~ zxrB_x7)3ft7>Rz0rs`aqTUz6>M_x=yP(N$jUT;rQqi=O}YoU+eF%Z`^IVk!H zu;Ou!@H<4>P)80fb0)6FZB@FPeLoUrPe&FxnC{$(Y&F1nW;O1v2DnzUkn61y-U71( zb!6{Q)Q7YTn*P%U*ic9I2D6%eZgYKh7eCaIgQCx-%?+-NGd5|@K5>XE=-W4Rqc;rn zLov}uS>Sr-?Iec%dgrsGeIEWHgj3hpGZGz$ zBLM&Bxtu}f^EQM`GRGZ(muo8D@zlz2Jlz>k9jsai+_M$m3i-LO#poW8`v|EgTL? zz6Qu3pY7^1$>+G7O`hN~Z_yMUyfWmG@dOniVe!=jYLXW8s|ggBIYJ5bxP4|QC*zWu zVKVtVmn+EJSr978II%L!C1c}bs3GGxXW;Ffs&JW~N;URfYbVm2`{o7K;Wcr?uMC{l z*yjcnRpT>Vt7YwAC0uXtI)gVDyv5)q&CcyNs{Z&lgPy!motBUzHva^86)rY-tihAX za#T+@c&@><2G<$9(%`iQC)OLnCUV5><~D=*LL^VW$Kd@2A12E-bIjnhj5d9y!M$B} zkM=wxqsZVAgC`hVVel-n>}fRyFEV(!!D|d|$iN=v72arMY}M?%H$QMzLiWf|dzcDm z8=Px!0Xf?pz)=R58$8Y6N`tG(vh6N3II+wS>J45;mc4m{!CMS&GPuRyy=2+T4;swZ z9(np7U3OS3gTHBGoU1}@tqvKSO_q~=uE7PGoo^T62CSb`_%rNs{oG?> z3v+~<3~n)aufYcmK4S2X24~=U$@9rq`gj~QIFWA%#RiWxc(TFM4W4Uot-*B$uOvs^ zPOde0y~|ufI5Qg=+YH`i@E(Kr8+_Q{V+N<;3Qqoa6dmV{n7V?Egkj0B<#T2RY^z-fi$cgAW<}4Y|K-&%YS(IAn0P z!MWgscPUxG47scvWpKH{)5vnUS!r;!!3zyuW^ld1>)JSBZDf z#NZzd&cGFk*J!@Z$K$AGcl}xUMnhJb)xOE# zZ3gc$c#pyR$phT^K5XzYgVS&iBgB!9?zn8Jm$k=M|4uf}-PjMaXGx(6f-x$mv=X>@ca=u$OyOq)Z+*Se4 zJq;dZaJj+L46Zb|+Teu-FEhB_;C1ALv}l8ovBlsfgIf&VYw$sXkB|qsz5LPO3|t+1 zdcJkY<3!XD@(nIFc&x#b4W4fBT!U-LgWX2d8NAZqwJy8I-+Cis6M2YRc$>ky4Blh# zeuEDie9Yi9T)KO=tC8iN-Zyxib59<%=q z6o$HmHyXUv;2j3&du!LP%Ka+5~HZ!CMS&GPuRyy#^mN_=v$j8k~Wbq23Acx}QE)*HOZ;B5x)GI)={`wc#9@G*naaF6Ca zRLK<9{qJpL%W#m@7Ga~=UN*K z-ePc*!7T>wHTa;xM-2XvEYHd^a4+p~f^U!Vgs8#!1{ag%;o4Y(CmTH7;JF6Z8eB(~ z2XiZ3c8|ZcM#g%BH<9J(-8O@F8NA2f{RSU4_!#*Nz09mMJQ(mevnT5Jgx*F*9=XIV zP-Jk4!4nLwFnAWZ)Gb?M@FIhkd(8f?p-|=)XfSxA!CMX9L6+x|yA9rF@F9c0G1$VR z4X98!Wtu^!QhSLiEe?d2JbLWyX*mK zrJFqFCR^NOyPND~(l41gBtw1VEP2BokbW@DvNDoW7WY?QI`2Yp@)uCxf2+i;$%<@n ze@1YMa$g0*JUr92eoAvvRdo`1LNt(yE^=g`>Qd!;vjgg&UC71Ug9&)e74PemSH~4d5-3jeC9k`O=S7+~`ONdS zwoOE>VZO&{|BgLi^gBND3d8&c!~9d&p~BY5DZ%rWeH^UOANf2ihX?-9lkHn*c=)@| zL+`Hmg;Y}A+-3BaJ`dY|gHtm~(!fwyZ>?ScQyk~xyuFSkwRa>K)QJ`elgVY!~nt9>2{;DJ9?VlVDAJlyK@ zFbkLamnK!B%c+Zf9*UargD3H@((sV_b-OEued+%VFOkf#UJq%pWGL3 zP10R>(AR*H9r(EqO4CEV;bF7S!#Dk;3!|U$dC1t=wn?luJiOxbFfE23s5)6k|My}j z*yaAzjBQwBc=(;qLjydVqNnn0UmKReLpe&)!@Y)wPkkO*;2~Fg_{is>#qhA!@bGt^ zha>Q?PkZ>%=OOZX+g#jlcnI*P7LZ}CLkrIN2i?8F=V2Q>czeS-*mALA=eN4}JZw6V z9=JbsLXNql^IMRE5*&vI4G;Z&9@d`#g+=2b&(cPW0uJBjE08Dhs8b*75JX%fbPUiJ`Wpr z;|EcwpKW-`@UY6~VHCb#>aG{c3ZI7`-*tcRN)JyP9v<|0n3j*%TR8E*;E?lq*!5o9 z4vveI)}{80&%-)+aL*!7_&gkg2QE&w;W@*@OFj?V;9-~^hZlVw(tg+023*Fpw&87` zhi~9vg!b^d&qEPB z>8ap96=+Uo<%ez8=x-VxR{1uJCzifrn`*$zHr=czDp~VG%s^cee+hhv-Lb z7gyNtT6^(~&qD(|yH%@)mwX;t;Gw7X@S@K{Ej)M!H`aHnhqrwm z4#C4n?csHwhqdrfiINj;`jrQ<` z&qLnFZL^8h+3MjZpNIYM;BHah`8=$F2d@oSo~<4_wLgA);Cu42-0cB5=8D<@58hUd zrP1o4ug^msJY1%G(ZlCqH#~SN3fSslu+PJCcnE0^1AQKH_qVNw1BQpweIC}pLvQV2 zq|d`Bc<{#IQ^UhVpNCEGaG~}v-shnj9;#82>*3Fahs%5(GK%pgYrQ@A9PEXIgW}+G z!@<=)2W#M9p1VExJZwYXTg1Z`hKI#I5Bx{%aL0g4yqkO;mVeTAf%aF!!z!PLN_fy` z%>@5tPIEbwWAv6u8~$c^c+lrzEj+9Vz(4|hFx=FpNS`C zdal3lc?h9q@38yM@W8jQz-jBiZiI)e^pM~$g4w$gM21Ru*npI6_yH;NI5&NK9%hZh zUk;`tLxML#*|0PHWqb<*)Iop$0($-ix&GRQW#c(`ov1#|=lNZv@csZf%>!FqjP^BY z-?@0SrH6&TR5ly&BmTg03reyPz*Z0Xm&?$@xejwD;;(;_Rg1fHy%Y67BbG}0ky4PAy z9qMr(WqgAib3``T%BqAVMX`F|y=lq)-w-5Yvv^gSe z^(6jd&IA80$2kyIk;uQx(c|0lA9MEq#~l7p`ro%Lh$G?O=k)oHIm7>B&iMbBa~X2X zd2Aba%ikxE3T%u6Qcv-zBSyr8QI6}$sVHgBEb7f}+ zl+`4g=t;)PKEvnlfho8;$aQ`2)AM(#>#w_2B6+*pDQ(C@B~LknSE-)u-n<@^3KrdD7{OXiIPrG1*^EAZHacgk(yxQ3ds;UbI7siX6KKX&3 z&e2l>#mWkmZ^eYINeTT={?Wm&w80eXGjYJxmW5~L|2$4k z=znPzS$fH2;olMK4a4b>Ct%ry@e00^Sx^EyaJo?SGP;f|pt_?2L zFCO8|ST*!vYlhViJ!9ZNWZ`Rwp^)jYkG8L}#z1DnztZyM)>N^FO6xE2$+IA{LmBXo zKbMqN;vMd#mW4P|R2u%Y98 z@RYj>$?# zEkm-&nZo3-^AM9X=O~j3r}Q=?_0By^);I^4gq-;8Nai|An5=c)Wm4ee+<|0`b1jo2 zPBW8iCu=#9-cA*h-Oh7JY^&C>R|F=a^;1?rJI#5B$u{RGlU+{fok)tDdzh?gJaA`V zh^@+yAW9Jwoyb=(Hqy)kE1AlmLYUAM-{HGwSqcwKtou=t2V zr!=Al*b}BSzI1Qk=0IRvWm@BD_XpzXPQhb=I;ZKeKsd3#_Pqx6LQI7^?%rK{c;d!E z@%K})fVJ-7oZqKnwzV&ovnTbnZM8hB4yBs#GN`vxUzb^>yHkq_o1#{6T6Ab;s4Ut) z8gEHK9+-xY@<7fTsc3GLav+ozYdIF`9o>;^dMkQX@6K-iE3NsN@$IRcW|kdk$D4sp z)#HKgC%nPBnt$UY9uJ(Pnw-ZT59AMfES2+ksxaR|ZLw-g{hB7lp`1rj(f*kOL-B`G zISuqv9th<}b2D}AIlpu|bPGfy_c9~Te$75@P)I$f`?1b2r-ejc8fvqX=<_R_l4)HG{O*GN3U!3oBqmnB!uUU}{(W35ldSUI<(GOi5;c2(`2 za;WrJys*p)H%B`jX}scBfp-Iml8#no#tBv>kM=yBTCE{|I2CR_@n^tb&%zrtQ(3{i&v=+U;f5 z1si|N`6w0Yg35C~OfCBR?vFVYBkehfKIfJGF%|!l9)Yy|lZ&kLvkGFF(G&Ij&?ql0 zz9+SRTBO9wnDQ=-2d2e$>q6-T6Eh2+Z7La8%5v_!rkB3qt$+h>rnm@}auMugf!Hhy zpJn~698U9m))Tv&s=Q9oXrx7s11123Zb}DD292DKh1H;hz|8&skZP^HQqNJ}cIc8ju{>ybV(ZiY6;mFyfhe^f&1DX-vm9sZ1+??6?#Rgm{sbx;~ zlYtTKC$k8`^v2331Fy8ZY#CVLM8>o?B2Nhoh}`94h;JgEE!-9L@d|~Y8>)hpjJ6govK1pcs_xFei;RComqN5A_K2K$m z3;zP#S$O@un*&3~L(rw4Lh9AMU3B#H2I2-pGT)@bGa+l^8#2h$F9b)NMVkXdlBo|u z&X6sE8P2*bfgR4;=W$ti_49#~opW9Ybl}z8up;Na=L4n0;X|EwpAX#Noc}^#Xn3SG zc){%Is=;!ZSX5v+PreYS?tGlG*m6#642*aFrx6#4iyH%Z&cdyr5o1&rr@Ao^cHV3Z zj1t#xF19gRo^0`*mknSp=rArg_^wL^x8apmSIE59IT0~zO`EFU@)m{gxK>Wa>V%$3f!)r9fB6<&RD{hX%di>>)S`^Am7H3yEV%gQ(f(> z-x28V#C8N?&Vn6*F3tx#0_DlCdp_D*=gzpis(Qwp>Z&WOn)x%XxTf}+8M?f)WJln{ z#v!i;<_F7Isk#Oq2o;Fl?>?uIucp>*sFI^#0%TRK)q3%(tDFTN1coH8bXDwcq?^mn z3Ui z!W`5~ggMyUi)h11cmR>yfbHCn#RtO6h;&*h92C7R zJ>YN-6K2n6!A>o}2LhKO%Th-UiheF+RYePIlVUTMhdqU$WN?M3>u7>^y@?TZc|PtXd#WLMbK}Zgb{V*py(GtR#(sh z^DI+99XTlaI>>4sJ`i|E!v@s}2Sr~ldQ4+NzYayW8cMzn#p5{!&o!8i6`oNr^gxX8 z#DI{A$bXrgp(i3a4QWi6N6^W_A*5X7ksf;6m46os-dNyNo#CEHN`zTpjPN-~%Y`FI zc^kz)*kJ=$zxM-JT`~03k%JZZKp2fkd-`~U_4D6*XV`;CW+VO}%vK)}W(9nlPa8Jq zTj40upM-S-xDH^$#_<6txi?rJ_h9zCm*^9@5cF}6jC}AQ$tVC92$z71g^R!?!o}cn z;Za~d?O*?Gca!Iub60P}6|w3!T^&lj#!m1pI*Lp)g9lS#HmEbkPv%u?w z=YsW-0{d#P-ju*KV7)1UYr*_Ngmoc@v!WKl@ zQ%4Spz8>uTSX=KOJ)N@O1^TO=&Kx(n(@mcFU7&m7W*8%c5F@=b>M0_pK^!3Z45om3yQ8}Lxk;|Zd>m}L(+ zPxRSH$=>|MuwWY;?g@S_Es_Yt8e9>rGm86ucU@h~23MY5VQ}SX7oG{cu=ua(3>;jEIe>8-CZ_HWhG|3Z zK=5p$L&md-elpA!>NCu0#B^Xm0aQ8oTT(+*=$J;KY3`G719=XLvM3j<|4vtTq0m{Bh4kVm4!f61>Fn z6MhU4`N#1L+A+ZFr2UBG%OJ(@WXOw#|AAzr4m<3YVRqOP!|bq}VfI&S%n}huogbkv z+pvPw1a1JHZV}ixB)@;QmCU4((`HZ2>^I zj!2%|bvf|BRhR2<0BR$s8FCiX*4cI@QBcI;uK^G`5k2-90zDVf5;@|q@$-!5Gkuw1 zwvs;Mp?}01_sv;aAt`6*|TQbAymdvoaB{QsU z$vzD9W9pa865TXpSpAY2j+37r6i~lphSe{bVRcJpSlyBtR<~q^|E8Uqz>c~ltI_YY zq0mrKhWaI|8Mr*`KJm)YQVjJIQLuL4(G&M*f*e1HEtb>L5r=12{H_H;ZuekCGaC2m z<(p^j0oD^+N3arkvq^eK+#alC`p=O}&6CZ~u`oGVenk?xS&D?LN<&2CBt%JSz6_^P zWTteDB6)j({5Far%`%20bl1I5-9Ctt)FK&q;ntV*e)Ayba|Eo(9BJaVYj9%O{J1Mrrog{X`r+zh|rJ-jTTRc=0nDj$bNnSAxX ztDO4ZIJ0SJ{-SR|JRWEE)N(8?q6ReEiCCzZ11PT82|Uk)7N)%!XCbkIrzRyioOR;| z_~NWJYRO?o>)|R{pK~Ai9iVmBQjUQ3I;1b>J}zP(g7xVyMYls`!Yd>@-<4@Z5-a1a zuTX}p?q$k;vPn5g_6FD??qkYLvLP8Hd!-Vu0w+DJUC+#;G8Vw delta 50372 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 diff --git a/components/esp8266/lib/librtc.a b/components/esp8266/lib/librtc.a index cfb64443cf90ca101537c7d74eab9a1bef254353..7170688c8c22014ed8626f16b7d16cbdffde6a17 100755 GIT binary patch delta 928 zcmZ9KO=uHQ5XawavN2zl>^8MgG$xza4OIdgV`H#Qt75367>ZCTB9e;QLJ+l9P%1$W zo>Wpt(1V8-+H+fT(TgMp54{F2;z3mKRJ6q+BFH+EY@}qC|IBY@-oE$ty{+o6_4004 zUm|_@NIH2mwW`_Rf0o8L1SBJY!w`cq-hfX-f=sP#tc7boO_!m0#Rui()9|LLNn%We z@P=6@cr0MctO`*d5yp2jylz%QA}tx~g!o9>(;5C|db?thH#wp849MF2MAd;yQYtX| z*F3RYrNNUjtud7Kxr|UWbo@8|kwTKwz&_hE^ow+uR``v}Pm0gv2_b@p2(lnsq7f)}=AoN?uG+;5OS&N+%`HXlB@ASOI zyxJv;{S>cQ9H98XVqWH$#XQH!Z9LNCU}N$SB@iV?mM8IIA!e+3yGysN3J+lR93V$V z_amUEfnt^dzr{6Xk5%U`UnE-x$uBps!5*v5pW=5k>--xq(^SGqf?hgpwhW0IT+CE1 z>^y6Oaa{G~A&Q{np@^f(L0G_hN<=QZY4^CKL|_)z6dhJ@Q_Ka+omu1=liH^{%mbL6-1ey1K-+#$rPZCBsIf1>n~VE_OC delta 898 zcmZ9JPe>GT6vuyW){$Lzik)#6w~*MG-JGpd9MP49q?APrg%B$bL90uUA@pC$lLcKo zB+~2Pp~9d`P>AfMQ>+k?K^HrD>KIXCg%E-;eVeiiwQl(afy%yu6&8?v)W>$v4YIcK)@t4q|EmeY(*bHgV zIj9qIpc(F}arskCCJ{p>of0oX(mBB)y`6HL)qD7^o&!DC2g+Oeb!}P(jzJa{bPymg zSzf5hN2>Cx$mKU1APdiA)%%B4`7HAPzh$YodP%DME$k6Hb)%6h#T(;OeUsO2mmky> ziGM~j(=C`A56&SUu%x{KhY{rvq(|nC1Z*G{1CAq>0!|`!1uW}M?c@G^+z6($${{E< z0LcfWC>%}0!BP-qgp|4kNl!|c-xv+k_kxNv2uF{?1xD^J97KrgdmIhwvMsqmG1*qU zb_aLvUKk%zgF#(-WxI474pxBBQ@c|vl+Pa+4$&yTik+oq-h#iwXUr2c!;@xOpRZFY z%+Jg;UFK!er3L8c2WqN~;{X5v diff --git a/examples/system/factory-test/components/rf_test/lib/librftest.a b/examples/system/factory-test/components/rf_test/lib/librftest.a index d76a39ea63527b1f26d62c87e8150e1508e6a30a..bc8061ab99912841d8cf44a57e7bc83177b306c7 100755 GIT binary patch delta 19422 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 Date: Mon, 8 Nov 2021 15:42:59 +0800 Subject: [PATCH 27/57] Tools: Constrain the cryptography package for avoiding breaking changes The cryptography 35 release causes breaking changes. Some of certificates are rendered invalid and the package cannot be build without rust. See https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst#3500---2021-09-29 for more details. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a43c6d4ae..6a9793304 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,6 +8,6 @@ setuptools click>=5.0 pyserial>=3.0 future>=0.15.2 -cryptography>=2.1.4 +cryptography>=2.1.4,<35 pyparsing>=2.0.3,<2.4.0 pyelftools>=0.22 From 548cd734ce052411d9276c042c94366d0a79b9fa Mon Sep 17 00:00:00 2001 From: Chen Wu Date: Wed, 22 Dec 2021 11:16:05 +0800 Subject: [PATCH 28/57] fix(pp): do not wait null1 send ok before scan --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libpp.a | Bin 249654 -> 249530 bytes components/esp8266/lib/libpp_dbg.a | Bin 267410 -> 267294 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index 1732dc3d3..02e907255 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,7 +1,7 @@ gwen: core: 231e0e2 net80211: bde282f - pp: 231e0e2 + pp: ec7ffb2 espnow: 231e0e2 smartconfig: 3.0.0/af78f443 diff --git a/components/esp8266/lib/libpp.a b/components/esp8266/lib/libpp.a index 143e90d2eb7d0377b5574186392c3d1432ceb185..93285db028416f53da4ce9724687735c1c5ba92b 100755 GIT binary patch delta 5351 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 Date: Fri, 18 Feb 2022 11:53:43 +0800 Subject: [PATCH 29/57] feat(phy): update phy library from 1166.0 to 1167.0 1. Fix PWM stopping in some case --- components/esp8266/lib/libphy.a | Bin 264160 -> 266024 bytes components/esp8266/lib/librtc.a | Bin 5048 -> 5048 bytes .../components/rf_test/lib/librftest.a | Bin 62302 -> 62302 bytes 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 components/esp8266/lib/libphy.a mode change 100755 => 100644 components/esp8266/lib/librtc.a mode change 100755 => 100644 examples/system/factory-test/components/rf_test/lib/librftest.a diff --git a/components/esp8266/lib/libphy.a b/components/esp8266/lib/libphy.a old mode 100755 new mode 100644 index df1c4411d7b3b0016429504f0b20d417ae7c1813..6f3b75e9339546b4d1535c352c244a1d18e87ba0 GIT binary patch delta 25185 zcmc(H3wTwQDk_%*xoU(6QPH9s6)hAL zFzDc|Vx@|fT2zif4@Ka3ELv1VR8+ut<6w)5mT~}*{O>#SEwWjy&vW{p=joY;+4Fwy z_s%z$HEY&oZ&J4;WA(2xmbOV0_bBXHa&B=+JYE=QO8$(;&n+tHZs~Y=Q>FB9rP{Ur z=W`F#`H7tPDaZecU$|AN|5;8r;p$Gs}~lfTz*>3_p#fW(NR?~t71actm!kVYi72r^1;lSGhx!?i8oAr zVNc7xjZ@ub-J_=|i0M`@l(hRSD@^scZ*+*-zi@baU1C069EqDH1(9=J_~q*T@sMWe z>knLblBz}Ub+?=}ZCfe53eP#GXHDOBXS66U(io6Z#fqu3D%5A!_Ftk0HELT_bly4L z&+FbpT`+lKyy)C`_rmVoRZ($8&*H-Fwf}yNp zzM*QutSRv!!$*&p@UxL4o2n_56;t~{R57Ds!qqcpOzB%V2UVw5OrJrvYT^yE&x4)( zkD-HqxMV4{G)0xOWU5_Y^!&oaF~A5$aT;Ok+?UK{?J-oh(r$ zjyq8Z>QPDEKy*lSF^`BM5HpSI`FXzwoUPacH zidNrOw9sF3sGIlI|LAp2>%LMC%*7Wbvy2HMeb{_1TKehHS>mQlh zb;vtu6E~$`fYjfS+x3dgX|pz^s(Y+`Um~~b!spTkZfc?)wZyM;yFU1M+Q>~!)$eHM zJ)hh4>1FWy>JQf5lH2vA+u=`BV>Xw)v;Owg%T_$T;JGdpb3UE+UCze(E1D0{FJ1EV zfCq~f<{TV3d04Z)>3Smvkd~?cz;a5vyqtflpZhMxS>_cMXCwf6dDcqHD=dy%^R-rL z%GvojtLtHvcsakVkLP6+t)kT>qSr8t`+O};Vd?2-Yy-LaX_h%F>-AHXh@{=2pS0rN zh@GnuL@6&PYfDb69XTyO%Zb%&c%X^7VUO-vyJnAm%rm3vbct?j=GW;nbXm>8k2;v% zPe<}=|Eo?9ZCCUAVQIB9Pw4Gl&CFeCrvC|@U)x`MS43(u;*Cd^DRir|QY>3)w1RRR zN~Tm~Vz^Z<@?A+hF;80ZF9F8{zo||0FLkHd-$uPlqNZsRZ(?XKG83D4!()}xt0&K@ zs4U<<73@m2&o=SaM$L?7URAixj%MEFiOH1}1=W-1RG(5w70jABsiL}~;QUdSk3PRF zzk5mX-%~|@N1c1l-&5UH!Nl3K3uaBmmRddQ=KSKKUQm&$oH?^vh3tDm_L7jjEM(V&?E6EuDGw13hU|w! z_M;*Dv5@_E$bQ1S67xDFo($2eL-sQvdrioGHe|02+0TdUb*I`1_2Q|7S|74s4%r(* z_QsICDP(U6*{_~rCnD;#Q;3M#8nWLA+1o<)TOoUU$lejMcP87oWl`@Z6R>xM?2khB z?vTAVWY>l4&qDSWNj6q_MD0r=Xzvf%e-7CPLiRTy+g)4(GNQf@pe-ZnP=h@MFrp4O z5Z30kwIM|muhR`FqK-EhKoNB!WGmSz9UW1gc_qv1V7|%n3Qha=Ufi^A?PZwZ?eTFN zKW4NBH@t&aSaZ$O2Tju-BZX#snXaq7w~eedMsHW(32E1n@XR4db+oU_`5)KB5MRS#J>RIV# z(;?TJS@d(YPrR;)*7|R!*jYLSO_iZ0yOODHHLv7){dL0B=XxC~Zddc*-Z^dI~nXG|<|=P#a*U0=KsILiILmCfEAudN=IOu*+?0i%cTV>u||EDvCB@ zpywcGswFB5b{zN)D_f?z!R`Y)2c6GUHEIBCcB2$IQ{AsFhs|d5tZmG<2&*47r{!aU z9#+4Dw*;OwHrk`6f4(tt=zP%QZKcOmN{S1TW9=tYbJ$FruuSzE)gE?RU|uIO z)syBEMo-ftKywP*6s{jODPMC!)s%c|4yutPey=oGm^=sxa z6p5|s8hDvpBhB?Ku-W6u$eHR5we%E!Og{;mz2s8KRNGW7Y>tZ4pQ+wbTVeBfyII?= zK7!3zaQYqUzhEcdhY6GW!ksUoP&2HZ5huUf&Tc(C>FQfI;Dg1pMwAF2MZ z@lW)-)g_`&xBk86u`@6Wb?P3WDa}-$nYTeFzEE3Xvo#lepZbt~BsU!$^tY$jaUE^q zhB_0POk6Blz-Ds#b~@)2yS*-g%`@&23=s_l~Hc!AV2Ih8HA7KY6 z!GLci5wz<<_SYf%c*t(nGzjNr@~n{E3pPhwhMb8f#{sapSOzGS0C7x>0Fe)3xfL8& z6`=svi;V%`G|1NTU?75G=|lq+2j^7jvH-exnvMFAo9c-WkgX~>z%)7Qf0^zp$bQ$_Wh zkpA|Ny*OmA4B0P=&Gu~vUK7I2K)T))s<1y~*N5y@+yNwUKm{SYRBRW&g&qwXxVG_G z-iRi6Y1G|3SnO>LJ$coZ_wd^34oOdGYS!eb6J|}Wn53$%n=rF#@(jFVF(XbyT6UaO zeKj7BrcSG#FuQW{c5vA^5AQR4MZh;$$t zqnl?du`hfn>>$Jl(U2qdC3J=G3sDZDeh)s7rU*}t*cYCwMa#XhncvH6o)BXw9iQL> zX|7ZzN9+rKukia(j({&{>;d7)5eJQprbgobS~TQ{ec{g>LyTyyhlSsWu9=SbVs!jmHoCUXuo!I7KPyWz;q zr9&q0La9uSIG8}Zld~P&gmNDB(%2;7$q@&Q&8J2hs}>D8;*&>i0Y%dAJQ0y24jNue z%^uUfPs5R0N~#VYNDoUja>T(=Sq?kUtP%}5;y|;48aYDGh=v?-aOA!f{t!yDu8%h? z@fj3I<8c+_k$Xh2FZ@c_`g43B-6)!sf_>pv!PZ~k1L+RYkR$emUkzJ-Nrh4iL_^NZ z>+7W?#IXiM(AaN9M2v0yk&2Lxj8~r?^6Y@A)!czg8d?6&nzVM~OUyrhwF}`y# zt`(jfu`m3`!XHCflBEBO@Z^XCy{Rkp1_YhB90!h_=mQaP(22>yM^KhBs61oy1vK^K zh<)Mj6@D$sLDWm@g)nSBU05}&qWxYgvm z6Z?nE-hp24j=O=8xbEoA5FG3ZG1$10^gG|nLUGyoUS81N>6{tVXblB1+Pg2weU7-> z!c7eKTX5qje}BF=xJa5E3U92LyRH$R((En}lJw!)YX*5!b@mZQ+|B5xxtkAS|A_hX z&#-C^I`{QK>jg&W=9ecuph&7F>u(SD9}HdoLtB^aSY^r;gctbAY+wJThSp?jGvh*)hXayAf2Zm77{(UwAw18Kz(u`jKHS80L+_qI+nV_f$4w zjfRjXm|sS% zCfoI0wc|&4vvps&?QF{!?c6aV_Jy~{?5L|}H)m+b+0FT=X*LoQndzF~lO99xm=XJ# z=E9NQ1dQ*Qk>22h>}v(^#@f4q5C@wd-<6POZQI#n07(6i$&(}Yh38z6FGtA~tj&(V zu@089_f5oHs-|j`_dD!)?MGu7$^F%I(Jp6+4EJ!jQA`<)?d4w{9C4txQ_*(CT&1*FrF$#bN{zVKayFG6XL#o12J5Y&?+_Jz0O?(Q^Z)p+z#3_FE#v4&ph zbIe=gy>GG7Hcs#^*4g5+^>N#5VGOPz5J9I+C2 zaEbj=Gjg)`N>M-OW_7xG;uHJA+cq(=ZNS?$C%T)Tedfw3-ox1!xY}h5j=h<^CH5~c z&8FhE9`}$_?M`{wR9yIFI;z+d#H}GD4mLkFtwnR6Xvh)!ADe<{-rynP=0g)h#Nj3m zLgXif=p!0(#DS(WHDzYwG;C+QnL@IIJYk_5q#R{3IHbp>d3S2h+%_GDRPO5RA(Fed z-$NC{N+L%b+|_Y>+IKB%5e+$FUwAua!P`VbjyTZ7frB_Eb`8!4sc;w$HoPCD9rXQ`$ z7bk4rHC|pq+?_zhdb`C#98@b6p1VRCvX*0UnegO@ec|niAjie(hq`Xr=5Y$fp=IJ- z5tCVPtv4*V2{&lN)I%@tn|9|m58`bs#sq)V&Y&nY!x}p?TCiERw2PwU=CM$ zy^G|mZp9EB1d^5ZcT!Fed2+;le>3qq+|G_NccVy`n{_yNgkHSP>y|ylRpjxG4Rn1X z_J^1g*Wr%rm>E9<=ZFl-&c9$g7lT|gb}o*Yhh}(#v#)dkZLgXo4FIRm3_Nwpk)b3rBgXIXnxG!k8;| zd?>PRiVq~tG>-U%v#}rlXl`NA+B`GcyD1?P`!@(;!zopYn;xmu-DxD4-QmL* zd3K?VV9w}Og4qH4umKIvmW1$e;N^nz$v+`RXBbZk?h3p`a3S!Uf{TH9i^zs?7OMS% zOMt%-TncF7Grx5ykNIbvVZK{Vuu1I^q(gZ9-_5s@SgMDqd>${R&PjyTZFPtq(B4LRaKvmi@VpsD^G)4nxy}u=*bZW`sGQQ9ikyeESiK`ktF&|MC6ErKz|YbBb1LM z>HjJ`IpRRSGD&k>G~|c_%_^(m{3E5w!XZfPmVayuSwE$77aP# zK(jVUQ<@MF$YNz+2kZ*s(eCR_M?l-p10G5+@AAW0llI7|4QXsAqZ1pTH<@2H2fcVYXBtM;uhJ-!MR50xk+)>|%T%*=IPx_QnLbE%-Qc@ckt1 z;Blrkv0QiB$HZX84C2Z7KuSZ#1?~A;a2I*lGU{h2Vj~>BOfY3v2xj$i!R+64f>TjG zCYWun63nLmAejBzBsh-pkl-lJ*aSb=a6ZV+f;$6`710WmU6D0wAx%Z5o*c0+d?9e4 zxluIahyzVAHGjni(h_9EN!T}CG<T3;&kzM^V~0_R!>@^UTz9 zAo<8zX7>nm!O>!W?T^n;PU1Nl9J--&$Pp@Lpi4j?@v)ki(>_cvr=2&0h)@EG70g1I*0g3E#Jm#olF0_LX5 zy3>FM2p*2|GQpML?S=|X75B(F;;4q>F2Qqvxx+HhT;LkP^MIcaJRg{wAvFtte=m43 z@CLz4fwu@=4*aHI&hB=LG5;%Id@PPffcd*X2IW*A7Q7NTom&U^Rls&51YQknH$UJt zz@0?17Pzb6b-?EeUJrbp;0?e(!;gS%&`mH#2!0iKl;Ewv_FGgmunl;+@Y{ha1@8pD zN$@VIpW|UD<2I8 z8%~@Umw_0{w#4%Cr8P0$B`{?m>);tBjRqH__C01+Ep$ji(T{&ILeP zg-i`OVqf@TU_HZWHam^m|7rN*D4}Sk6TR(3cK;{#h2JAQ7ik}4&DU&5pCGega>Tyy zrNCM{4eL-t?g00HUmRS`bkH0GtcSP?_AwDWIbvUU{*N!}IfG@?^ILf&d%XZpj@TFe ze9`k7G88`j5kAnq8Y~Wy#KD(NBPgl_fn+Z{2uhCF7k)Hso$WOCIR+YX_BlrQG1Sa* znz<<0X>!B~UmWwr@c_!PtS}n@X{qq!h<)M9VQVfDB-UZja>2gvlVIy=r}>R&$PxRF zPpD_bu>s{YR^Tc`dQNz9#KHFrm9X`hPQyBEm>jV$ynWFy3M5iHooC?gv z85>oEx4{6+6s4iOSa1f)xL~ea+IpNe7tiuq1*a{8YI!RJc=GGu&cHDq2c!aIVrm(O zm>uXVm~r{Cggo1iA#47JETmjy^5lqp;d5HU2p*V5h=?4qy{9$P=X;Co|4;<;5EYlY z;SdMkmdpd@u7eirb(VM>@EqYeh1JBjxb9RDm*WG8$0gYAcu+NW2BdOieY3-7vERX0 zr&m(U2qdgaU$j2+S=zp$jiF4 zr&Dc%SM#nB>0zlsj@TFeMd7!i+zy|X7Pbgaju-D(x(6r0jUi!|cf&;-e7j!9YVy@mzG%o1t_rp!>3;&_;XQyz(Mr%`?ez)-Ch<)J?QuDRB?H(MtuYr*cA#1@uNHucA z{@3Q^doVL4W-n@>I1KAjxki_<;!xM#AmTe6E+xiVj-%`&7=`;v;tr?DCx5%capGO( z#BBV8VVhT7PFYF2THiN79{+`YtD10XufN`%o3CV8gB)?NuTG;z4ofr9 zkRuKbS0y#Sa4lzvh8(dkd~0gvI87s9&P|(T-h_@tj^G;v$0@zZ{A!t( zg&#b*op={GB;5U}7@wArI8fp!${B)FQD!1K`842Of-``*fs=m;Ww~I`?nw?jcQM|b z1o3%*1AW3?{2=0(*kAoic#$|S6pLhmLv9s?@A3X`AFPq*$HyQzVM7ip0iR2pI!if#DYAz z1)4Wd;wT28>qRef8mnm#doq27|k5$`h(~Y;bE#FTu?QaL4;6q7R;dea& zpO%DMC*k}gT$qIWB;m3oJUR)VS)OE6CgC|rc)rDE$~v#NzS#U4MaL1Y+o>JUJ;D4% zP=MnW8}Hxnbq&u-q-mrCS6gf@gZon4x-o4aC3tHR-kF5!lJJ2fd?X1+{c+q<}lE8XoI+O=aFyDIxI4udcPQv*~xG)L#Ny24Gcr@_@*H$@kxx;5x z(x`C89OA1To=-f<;ibe=_?H$;`3;c~wew&0#-w?-Ma_wb?&LinCH}L#wKqz+P0G)r z=C(%ofsZxY*JN~S0{CpI?vxV6)ic#Rm#Xu;W+|rqRdnF8%f?W(M?KvP1d<&_9ChoBDA{`p)JLTfH-Mck?BSz9#*36oX9<7MGcED7st{ z3bo*Q_Xd)oI4MEXlg;laFAvGrB*`Zy$*awekSAt__XfU1&Kc9`$T6iRj}9MVp7N;k^*>-Yq#gg8C5SRbr1pB@HG$z4L>3Qu_@S8hiUF& zDn9pGw0t_$R$4mVY?}cYx<%hrF8s;p2VZo*9AotBlA^BSbhhC&=bh+E9M?h*ufaz4~3YPiOZAg#XF%8 z8UOCSh+&A?Ng=)rg*b>1!(E8FP>5F%A~?i1B!xH>3Q^hu4_-DzyKh4w4kd-abiL`F zo-z;W-RAZ;@$-WG4em7)`*^c?j^42?@zi17+2O^^mv4HfrH|R@?gA+JxzTSyvH+3; z_UM`7x4ew>DoCnivTik(P*Ru?&=hTlq-`7A4!ChlqGTH+ymzEzk+~fb zy~_OfwwGnr(Y^gu_kUsNzQ?@72vJ;W7Q05G??6(F7h9{PktHVQ9Y~f!@@v<~Xi9cN zvK0{+Wtq7i60bOJPQ2~4GOOrc^?JkNtTCGzVtFpE3T8kf9W#G}B<)Y`-kK5aH_dlI zQ3u6Yrf3IdE56OW$D!Al3VPG>FoCX@%XgrOX-Sd?&2y9#Lb96+BQJd|yulbAHu_x# z!1RA1YvNr581rVsnt0S)Ldn67lwAL=mv{D7y!ZM-CgCxZQDp2E>iouTZwmILot^Ms zW4K0Qec++06q#wwcK7uU$M87pAi}6ngfVAu6T&*m%1*9c`Hp+0XZ0sc_D*zfK9ruD zg6f@KM#=)%|K{vRV5e_Gm4j%BRh~32u}UfKN{5)DjaZ~#@5CbAumksnB3W&kya&l* zNSYe_v6>d9&wGe6^j-I=l2M*9S5UG7FK|9}4K0S`?6RGB;{i7%Ym$ccY-nh6@eq;a zrhGR;uXxYBO=rDl%~6J4-W5L_GkOC$c=r3~;H38(&Z4zu$or7&hNOe}ZZjmeQnDNp z9tuWz-aJUjaY%Z&4sLrN4XsRyvd(-(N%7fuEoiQP1yS04fGFD`$(JZEnqD73QVB_s zi&FUkq8v(+tTziOSqVvJ^BueU2S#cALBk38viXpbt&ntgQPOrHN+Be{zOcb`*#*gQ zND@vmmXdNv%B3$G&CQg|E#U0);$hZMvI&xHBH3hKr=)W?yfkyOdz_NRyBfC2EhhUz zNamp7+3wg5{g6>`XT3%?hgZ#XN)B}AuE`6Xd4!V6JxU#sWBZzUiIQn}nwTn!=tCZ( zPn4Q3ec5W7d<4mMNEW*8_W1}=_CperC~uf6C>h%W8?2KorsQ~C!!>Z5d76^tkaRZJ zzlz!2^AQ@F_G!Z=@s>GC$p%RBWW9V0$p%P*O>?^$@-ZZJkaU&xLdg+Gf=zRWd61H{ zp7@E8>&v!}(U*+R8WzJ&^A#nXA?YRSWjCS}LsBk-e&6)k4ap=(E^<*ScYDp#pa>51 zF0+t|wNT8I<+2-_9u$=l<0JDS74dUVuDP^5=t<${4MBFBE_)yu4M}s?%vegwAqm$1 zUUM@g(;yk|Bx@+Cgk-cdRA*kNWGf_TPI8=*O^^h$@|nrr3&~DM+M0KoV~ZZP7rjmD z$`@uj6$hcX+y!|AiuBYk8V0n_yhKS^39mbD$JvW{tA+&s?Af~CH2H+>Kr-D$>GKJq zjQO%*ZU5O^K}l&Zo~?HIFQz1aU&E3+V4kLA4kXL%y^+~X$!bWdu>o;g_{JQiB&{!( zoZDRL(3iH~G#uuGW=I_*gCH60mjB#3L@9-210pcW_vS%J8m;Ju?|P!<4bejfov%-=lC* zR*KBD|Gyg!-x1hBh~`aC4Y3#@#<>t_a3zQ6gL<1#mE$;;6oP-JAh{O@5MsRzk?0f( zaU3CnYv}Q$5Q9S@R$YMaPf{R|#BMMR48>b@6eLEN1*X-oX9JmO7d(ZA# zeepL0PZ`!KPpdQhHr+4+FFefVRNbQGZ$hqla7CPJeaLkuTv6xxQ^@s;2G?G= zQqc-lnoWz~(zaIScOlo}5oY}7UaOYAe`=M*C#$sV@YAl|aAAxm8)B`vx&CD@)(f8G zHMb&Ft8yqgv(1vGWke|Wni1w#UwEBT)-<$#^WRB02R#2<-t!M!ZlEon{At(bpLAvJ z`8$_+_H!?b|J^ltLX&#e4BPEbxN?8eW!mn;Jz7$fVLvHtIpL>WbAH;j=%-yP;YvPe zN!{2Ga{aF1D0~odJ=@^=Hq_Sd8(fj}Q)g!_T<+LqX8)bbt;7QG$=zcWS-gWnuIJt2 z&AdYRLc7}W;5x!=%+#$~P6Ur#|77|Wp-SA@Q!P~j-x+unw!k#skEiLGa3wF@BUrlI zWYgx0`CwnUJrv^iqwwyZP}toZle&lU|A&73vugf zBC{qYabI~^ksc)_HGSH3_M*+qjfW${PA?7SA}BLAZ~t&v&e!$td}H1}9LY=UtKYIx zZHlWc6IEJw_cujzKC3VKydK=^UQV4WVU$JYeiqNq0O}IS*-g5{>!pi6Ch9&>ZR!)p zpVi!3zX`t%`+yw&TIu`s@q&1l<~i@xf1Tdl8@k6UJQ)3Bhl_Lmv%aiZ#jEv&MbSbt z=f5L=>#>9tdU^O;pvxJcMCUB1PkqjEMT_cl7S)$Uwmu%ukMCNx|Mnx-cZpQgZXve|?{#zp*|0i|h9p zvpd4q*^8guaY}BRoPA_Fd%u`?8hY?0g($yZDSt`UR344otB0B&jz-Qh{Xf@f;}0ra zOpxU(H@jO9W4YKbke2}CpXK@1`+VWwP2zU~w-Wx(z$Jony_(xU>||a%7O8C2Rk(7L zfq#Xn$r;+IcH|F{W?llkO&R#aoxT0V!}|!9iKfe(>!g2d$i60I-xRX%hK+4N{`Oo` z^+3q~6du+;`7x5B=a?^ljEpgF4A;#~?-P+5%zvDS^lgeq1f}sR391t(B5e{l8|^a! zcUIo4@_B*bane}KAuJXgL%Bq7Ta-p{Yn0Clj-y;J80VpVTw=`5z&nNK{Oxu)VQTDmGE3)gMc-c4bnNVsV7J53va(TgUyw<8kw4%XY)f0 zj)tp4XE6+ZenIwg(=X{ zJe_Gq>S)jOa=Nk8@<`uk?$^-{iDiJjgeJaRa5+n4Es?Jjo*c0+{50WNcXkrKEeUg> z=+p6mbSE;qKn^%p`QqTp()>VLgiI05MYTh`=zLu>?&UP|VI^hcn_nzI{6 y^U_yig2&>}@rcIEGG1_c;wJq)Td5}F^^EkiM)P4k3T8d!M z&8O&x6csI1_#I*`Dp&`oh)|Jv9uyS;6)lRIf33aWLoTQKJpKDWPrDz^-RoWN+V39E zKEu6X#bcQV?$2CMC(*X!CG9%qcjyq0=f;_mKjZNZdF|U~}H znIrLYj{h(I-j|j7*N%h}ZYWmjzj7psm5#;!dq?7@Dxbeu>HpA?_)k^zGxa3?V?F)p z1|c z)QD*}51%-B?D(mr2V?h?PN_cO`IFTzy&zS#;sVn(rfWRkyZ)h?VXEB&MIq|Uz5N^L zcINe%H~9I7R~(Cn+)Fn+bmcj!3~^tWdCs)eR4OQFSCDV=PI=9%sg_!)6s7VNQ;xb= zUsN{We%+(8x!&k{_43+vYM0k3FJE<=c5^(hW4vu{+dS1_bi0Cf?M9S6_n>}8M{h5= zb=0(p!zYi9_vv3WaCpzFuP%GX=m&F4S2jqk%%I;X^U_v*b)p7pYKVh1UV?*Z(%JHo zv*m-%mNz-l9*ZqS}zminQ-LcEY9+-YBFJD$<&h8mk++K=o<0ed)IDG2Z+eQr^H}F zX-cNKp#UG9h-MPq0+jeoNIy4Z-xspyh3xqudqK#4AY?B(-%hB9&L`C3ko|DTUJ|k& z3)xFU_Og(@{5(66qMkU9NKsFP?59KaA4B$^LiTeZdv(ZuKG{xSzj!g3fL#`{{~WUa z60%w}k8uDs0q`3O}qMti3&C z?+n?yL-yW~y+33h4B3az*{mN8IC_q7_QxUnlaT#c$o@QJpA6YwgzT>Z+t!Z;d>s%r zPf`B}+24ljvmyJ3kX;_KHTLz2l%i6^uIw59B zVXvoTdgkFyDYHvwJ`*>uv`fh>ed*dv^EUwVY)_qOc9Gf!>QhpiNPS1@8&Fl-15~~) z)BFg!v1S(tB&@0yF?{&O*R(hy`8Ky}i zuZ@nH%Nu#`o9=bJTrWqP&3$yt$3v957)MmyU`iW%`x8Ue+cGA+Xhqd96)Y@g4_Cpw zJG)o~!|v=7m4VtLD4S=?k5Ki`vq!4dVsj6Ps?q9FX)ViSMO9q)1<@DA5!^OJ)mW2~ z?X^javzKGAHf7@T0m#_=2{@v-Ml6>&%(7HX{SrVc;QltuM72r$pcKm=g3Wvyj;NZf zPKEqGh`%fS2{qN;1F(P_uj#4=ddxh z1Ug8p`Zm~XdR-h*HCxRVyQ8)5R;94hfCpH6j(Q3<%XPQ*Z`2yt9Q#_>ypvmM26|4>*bo>ii@D{Yzl8LCdZGVf81m zSK0Rew}(z~)Nl4jff~QrnUXfjbVH zgJV~+dQN=@8~u>kU#+U+Hky97u%A~g#cl&Gic4`9v0Kni;95KY1Osp+qUz6T7;Mf) zGi(1vO%{8KwO>{Dz-F&_-x5`?tHrRHT(4{EmFL+F^lRtYQT<_(oybzv^l=a@>;hmp z!H&aj10t%{sj3&a5$R=@%U@Lk*g;}L@?i6cq?gsdr3yp-YhY7%9gZlj{kMo8@&x87 zL(c@k-jA|^4QfG!0RAlfqy)&Z{&!UwY>tpye($OEusP)J1bkoZg3S?i`Yq~X*i7WI z)P?#R(MM4~TJ(WRL20(o&IxW7YQUzr7mldfu3Ez833a2jcdE-^@YOh?YQOru=u>%hj;e!dX{f-9ut~Afs5-3H!(brSprdN1=rM%oQ9XU~ zJiES*RB@x@w)2lwHP}o}Uq?3*JK>1BIu8W*pFudHxGG&P0lHcHGc_1C8{@Ww&($c{ z93eNPUzX2=eE>F}(4y+3x)*kk*zi)(bDc!h7wU1?IO`Is7FrNhU#aIoIxt44(Mlf_1RF(ozhU9gi!Xd&$H;kycCRQ;fypkC^?4R~GxfVTFVA^StIT?Og- zNXY+9$gb=&l1uDyEMzx=o!}6^Zil#BwFwCdLw4VgJsdViWDJg|(t4cuT?4D?J45>U zA^QnmU527Av4v|wf~_I@Be7itnfg1w?Aq4eHB~|{Y&w{|9lZ5rFBEw7v}xJNd!jEE z{x(+)&yyI-BXM^04h!vOOP*Xa9KP^8YlE^>>LX=!F7+DfraNijYJek#HP3ZT>~~$OqEB+uR9vLZTLtlG4jWN{%>)I>biB z2NEyx>>xQ}U#b}jTT9HBMMI7_=s__x`|yEeVqLwgK4Odn5jc47$qL93`=a4G)cf&) zv{f|Zi2eO$d{?hYFbRAE#Sr7*CJrWnr-R;w52U)HAxDf!*wnRR5^}{o6>j373o~E` z!_`$Z4^yGkT+xst_Jv;wJE+U_ z=!ULI1*_*fvC+sv2U@O1dOY24krwDyhgBBkQc zT9C};X^zNR~`nbvHfhBO6SDL3g!$nz;XX}Z#V(z$nw`#axEdGl46a*ATm}8@Ck;8V|E0O_3T$+8{wxu9CURn5_!zL3&F~q~kR$eY8n2hvBxpcg zb{RF)f{Pdp=$ho_duh7s!A%VJOt>)#kM;6;g;f-auktaT{9dcO!t@P=#8oj-n zwf@H3*#~3sjd`dK=I{i4N;T(*UFhy9iTxAi(>@sXZKmy&-tD!|I8{$%F?5(iLhPS0 zZ(Ql!lm4S~v!VKk8UHJrhi{-LiSG1 zwMNUUm${I}syU9>7rqs+_Aoq1Z{nba9I@}2XA!Q8ysc@^0fjpkE@EGJyBg&M&b6W; zN9;$8*UuYVyAm+cU&YN8O6*rMKF@quI)1-jc7*bd1BPH%@q zhRU8sN6d+_n4Gib%YNP?+B5U}V<(Z`vDsSMaX*7rcU>X&g;F;{K4RhEwcw5;;S9^cZ`ct!M zuvfF`r_N=I)Nl>7MWndx%eJzrMcx#xcbGe`L6IGUs-^XvHEUWiT!_=SFXXR zXPSK|f$W=WaDmxouDurL=1KF|wH5nkM?{M?aIYk)k0-9B2xt!M)A(7{6U*A6@TVps|on+m%D?d&V_!*tS#7K9iioG^nS~>USpkf!ft%BGW-nQrr2&AiU zP(zLw7pndx*h$4bQQRB{VqbXMLBaDyLykDmED?SM@>)2wRKHAka>PNi0F}PjHQgL3 z@v>_3#S>Cp9I=+Jo5X$_lQF`pc}+{_hR3=&Kg7Q9wwt+5(@8Ysh<)MhXdVF}3E$n$ z9O0eBqPyi6-T+-&TsBnlbPqRwABh{Fc1h7&yDP4Z-p-64h3%)k*)$3ZxxM*ll-)`@ zjrMw_OBh@8Su=mMH#i+zAFp>zJmW@tw+4@u<3YtbxG5wK&Q;r>%I40SF${8Pd03+UdzOLueFHioyIlJFh*r#E|NYj<_jC7@#kZWf9CuI9%v-s`%v zc@5X#yv|N#gQL|LkKKw(gQ$2W1p6Dm!eBsh#3-@rRzL?qQ-KN9+r4hv9pWNU1o28#(*771R6VIPadOa@+P8{IO21@5H|FcK)>K ze;dw3xqGu`P!(788&ZrMu`j$G1;HCdLykDm#DTSFxD;7EIpRR`jqt~iUu4HczWi#9 z`dNS+u`j$G7i}`eSG2bkB)Ye2@6}R_9I-F_4Z@E>o=bgC0HhJZlOy(pkHF@#u0s)0 zaLa)^CKbEXQpzkJkDWsb@C^EJ3HujOJx>nq2$ccj~w5JRQ1c^Rj~cAL?!3G3{@mlQ9W*W`j&yWa)B04+n>D#3Y>Qy<9=A zj#zis1Y*CJd1jI~ys7jO`>TreaBkwDlXkMsnAVf+EyER)yVH99}PfqqO zZHgIWVgqBnEwotQm?ZtdRG#A9-;{5ik?bfW71P6#q}$9ZQ?R|?WHP2=`QPL`_6!zW zga|QQT*(pp!q)=U{hWTLXvh)!!rR_SZFVUZCbdXfXXl0I36k4oO3X7;z2RMp9cM3) zeO>+b0x3LBWEBI?^~vvKh=(G#b>67W{^?$gL~^fXTp>~V2Y$LsUW@^d>FgAx<>K9(m(jF_)Y!*U&M4o$<_K5H6G$HF>m+M^<5qnXt( z4^8)O4~FJzMi_t(q#tn*vvxky5wmt)qlsBNS0piOtRtA+=JF%Y-c1qA(>@_M4!lTk zHu*n@kptsN!L5Mb5S$DAo?y<$UcuNY)G@&Yz$XM30)H#G2k-@+YY_GJs)@$+2Ikkx zXlTOzo*+L-#P8zSgMkp)H%q`pz>f+)1o%n8Txe?rGw4@>i-D`AxH#0b7CaL8O2K1* zOHvX}G!Di@9GX`Vq?0(<2y(=}@Kb>`38bj>k{q!w{0!KEhEF7nLykDm%nCH9U)?Ms zlEi^%b|6ANT{Pr~1I?TyjeYP(W#sIGzcgrWlIBr~LykBR1e%v5!iyo>YI4MZ=Fh@E zjeJ3p{vF}T5eNE3Nt(Zlh8(eI680B#!EhZC(PD^*gFv4NzYF=2q@Z63PmVayFHO>X zFB)>hfo8eYaQuL+|2@)wc{3>KaoaS-%Y;in=GV$KDAIjO7>4LM?#wf$d{Bw8vWa>PLeYm+puh=v?- zpm|I9r;)#zr2m`nZjyMRkF-cQR&Tn$W zfu^?b*~mAa)1&_l#6glcD9}>)t*EHC;1c9p&lSeT6llN^2W598X-12N9C4r-PdDx$^6Tj9|1UBb=6lOy(p&rQ-y7Y#Y$K$B0+ z7x+NB9|!79*c%ZVzBmeiH80snWjNS4a>Tyyn}q)sIp1MX(+D{aVs?aYbhM1_8R&x9 zA{9I@jN~~QOkH0(WQOt?=xPv19RzdOdDBOp!)_mrfH_U0gy%Hzaz;%I_?Ln?1$PRr z1^gSq+1w-U6(bJ3P%x*!-b)}5hkCj29MY!*b2!%s<_Ou_3g|lnza@Nc;CBTV0`Cyq z1Nbm-f-Pmw%f&Ge*yC0Jz6dy7@DSi?g1I*0f{TG$3g+N(Q)SsPz}*D*M}Do~ap3KS z3e80Bku$_G6^>sEo&n4qmVssgmkOQ@{0G5vfVmk`GZ*+d!SjIE2wnjEhTuiO?+NDU zZnhZXzZk}DaV!D;NHB-`8^KF~)46q^vgN>bBLrRnY&SpPmB7tJvkJJC;1_^92!0v3 zli)SLJ@Kn^8+0vg#C-@BTPQl*;e<4_5EqyDP`-_gaPNo893AQ)c z5niJ(beV9p5C^}pXeGE7aA(1Mt{x;f4m?XR&vSc^i#Ry z5(m#HX*5s(@$BXj>{b(D#|GmAX*LdGYJM#^75O`Y8Srm{8E?B_HsVXcYyjKBIDGy| za9C-ul`RCvfx8H1uLcXw0p?9K^{s%*1asrbg{?U+NXv0hLyp)NJ|9@$<}~Y^#_j(! zd~p;|#4iqz-p9c}FxCbJUL=t_{&AlYe-+}ci;o{+n-}H5J|=k ze$q6MqFX^A*$WRekQN9}j@TEz7`DFDX;_9q$r1a)kECXb(>x&>a>Tyl6Y5!UtU*481)2jOtrngf zaq#`hIM|veG!o0OVsga3@btj)eba@m0Q;=j0!ey$*@%0+;VFrk&d&uB!|mn@ z_=$btn+e|y`AYb7TL7esgeOPr3%?4s{-x9O7Y#XLU-%cOxkNNYA|grbi-TJ%8^rsm zmsx;!bV$R6Cr9iHzXrC>G4p?qS3o)D$=`do>yDU1T!uhgD>n-S0JN zn(v~`=Vbx4tVd~LU-*rTHp`4hiP}6lkX{O;$T!nnWFB(?UqZlZc36?xC#tP5iGwrv zxbXRy2uk&*PXCSY6faNGM3P`z33O4ooM#CJJdNQ_e}j=ZyAWcHWi zdbZPKlTSDtC*Fn+q*NTbs)cqJ(7Y3uq<`gbS&s+2rn>1#M?ZipcAeX8iG!!aB4B-w znO}-8w(fBShmhjtiSz*u79&UO&oO^1#jDCn<^)P0tGoz{Q1-X)P=?}S2#JIJZ6s{0 z<^GGjnkBNGjUgqImcctx6eCCM3qOvUU%PhH6b(6IU-(+oOm`YU43K$y5&pnKzQ(oB zx@dbnxQKn>Fs1>>~}bvhD`He2Pu>IK8M|N^6#8s z+c?f)Hbl=W%UJBaol;tK(Wuh&NgGS=cqO~6-J{;TdVIWRI))uy3qGBMRf7sXEeY33 z!r4hUHwkx6!o8DlQ4+qWILR27gl8n-ITo8+UcsyCf#ykMP4Rrnl-dx@6U-ls1UPQ7 zsr(n5sJNwN8beC(REy0Ga9=anxz~^qygmtUO~MC~@bM&kCJ9I4jAK4U=ya}hq`q-b zMP+T*c#ouX8D=SUx(T@94)e8vE_OJLc!a~Xh=1X5Hu0#^$Gf*S@#852%TBNLhNOAF zjF^mwZsyIC{7K1Qko*mo;}=F4NCYEi)}`tu-ie5LX_MFNqEA5K zpDJ|Ksn`m)MYO~sx&a)0TzWr7Oy&2zW-a)~Ov(Cz&@aK)GSm-E(x;kh-uIg0?+1Uy ztiE}IS#$Fqv-aj|WG(WrfhC7J{;YeE!cZKEpz5Bc=Vr(YL-Ne$D&!-Rxng$Vs!Kh}mq9rPm8*^5buXV3`q(xJt@TD zP>4c=*yAQ-Uns;}gy6F?J2E3F#8;sZ^{V53&$goeiBO0&uehgLhL~xt|G=wTsW;Te zZG~pu2VQ3SR!AmFEwjwil;qdMBMK!kv-bndq}J;dot|s%rDP8zb6uy`P?8G?zu91v`^-*C zM%Kj-Gfku2UNw`p4U+tI_bmhSn&^-+S?&1YK+a@tbWgnnSR?b0lDklV+*4! zGGi%O3Q0@XmL=N}Wez00Wn3OIf2L$3B-v(AWlZDekfbFk7Mm(Npg0A^9v7tZ4g`s9 zsOZqc=6Xst;(BsKmJ20oAPJVs67w`AtC~{64Z-Z8q}4`uqs!JlX1=9lQ8WCJfs?e_ z2}$OA?xi;+OHH4hkkrD%UJECg1l%K$0fS zSZ%(bWDO+kOx7MWBl1B-faguOJ@B4}w}UBJj{wv5AV5AO*%IJIvyhTj7vn{;Snn52U{HVPMzbL5%e=&DavIdfbd7J^> zgtu4%ylS@4+qpIV#KA3-$UY2H_STAFdfhbI2gxx=2Dp(dqU01L!9KdqOroR!8_^VZ zvM;w$a6`P(b1nU=Sx3prw)ld;9NdRyY~G3gP)BC#Et9n$-kf~AY_p5S^xV&>*zLZ3 z=4`!VN+?+X$-SsAD4}MKT)inL(7yf}{yoM3eORzKV_Uee*cIOW|#0*3ml@-e4-Wm@nwv2yY!T z=?#Q$dJy5KLK4jM2d3LWNRC0$(UcrSfW`0zQ}Ll$NN;v~{OFbIAZFfTfHRO_TMJpgZ>EQUkapr8oK?>2W)!5?pCna2-#*>naAd9T?* zXAYdhWGNiR0B?pQ7@z&7(P2pDLXu{>9Y+1x2P#J3pqWJPB6#bWh4glYH>mrtSx4_G zc&~HePc!^DNXAL`j+(3^kfavi_XZ~K2$~1y5pjNOO6Xh!=UAElBPhS-V8u%P#H^-- ze^P&wdHhX`;L#%(!MTSjw#CnkJ_<=OBptX2nxywWT(QPJH-q5Si_NP?vE$4+iufDh zo{AlbOYo$5oP}F;;repB!BNC7{H$V%zc61=G7^#^cd}%EgeW5+;mbNk`O0+r2$Gk( za!ohdf-B=xO5&g6p$B^)C10C`l+3;yuYg^YHz}F>1)7@TB>yl6DH+%kH}KpSVy61X z-h~&ZeO)nI-(utt&`vPl1t9RbO?4&8y=;fEg{|xxfagMV35D3xFSv8) zQV|kL_n%zm$IrZ)G0>dbpq|;N$KAPgIt^Fy zyUKpvweja&2Y%jl`sZCfw#DShOKN=mpLLme$Gyzte)joUY4u@nCC^$?1v5jg z$14Wz!H{cN;EH91s`^8J^DGxfh+d8YZl0=d{|T2Y!sDT8SW1?zmwtY`pM=Ymiq;et zw|u4*{mrJRu2DS>9$V(6WN0**hU#IfB({S^jUYfC?aeC|? z+}Pqu&+kaLnJ=p8x|JeJ@G{bTa?)#h{(p&B*6Nh^(c>X5_kongl|$Ub#VJuQ#4UX| zW%7vgxk~x@9oxq3f3fH-PdCGUNa z)f*#JT3h{j`C9xmyZ5%Rf(V>-F91<(`VX({MnecglNbl)PP@n-|G7V}4Be zy2U~k=;)GB+}?8|=L zzAB&97Vd&b{F2PHyW>sbFj_?PDcg+Wu93~BGzFXE#V>9;x^bOG$H?Y*za4QQs{5Ei za<~}6c#HE`SQb_;lzW%HOBEPO)j=t$|!hXZCQ5>z1Zxx)2{D@#=_CF|NgCf9r$cd-ouwU#VzaIzR z6OiXr9TA)Z{WpT+!1*|IHGCl5$?vCGfaIMxd~x8$Q)zY!=`|eGkR$emKPY@Ye4T-H zb$lRkSD~I9u`fKodnC`bwp8%OivhUE=wPc0QAl&eA)OGuP_SRa?7AS*rZ$Ha2`}I5 zucA31#C|Q)I5pCwHZc<37g#qZkl2r!VQ}M5Deq2=v`@dDZfvTY(+TFS)JVg`eSjT> zCT2giMB_T1dZ$Bp26suR=B9KAYni*Cz#pV(Ffw8=Ft#u>H8k7YH0LEVWB=xy1)qWd6M!Wm delta 127 zcmccjjQQR(<_S{lMwZ5=mL?V(6|LDhpltKW0)b+itJwQI;Ub#_0^cyfd0=^|kWKC= yB9mXuu9Y^mGBva^GG%ZqO;<3qR4_6yGGs6_H?XucHQn4a=Or^^-{zbJpMn4(uO(*y From a6fb3a7a844a1307f37fca8488da33c2e35cc815 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 8 Apr 2022 14:41:17 +0800 Subject: [PATCH 30/57] chore(ci): Fix CI env issues --- .gitlab-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f884330ee..9c007547b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,6 +10,9 @@ variables: # Versioned esp-idf-doc env image to use for all document building jobs ESP_IDF_DOC_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env:v8" + GIT_SUBMODULE_STRATEGY: recursive + ESPCI_TOKEN: $GITLAB_KEY + # before each job, we need to check if this job is filtered by bot stage/job filter .apply_bot_filter: &apply_bot_filter python $APPLY_BOT_FILTER_SCRIPT || exit 0 From de327615db9d54b9ad56b13bf58d97ea4ba7a6e6 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Mon, 28 Mar 2022 19:09:45 +0800 Subject: [PATCH 31/57] fix(esp8266): Fix compiling error when enable Wi-Fi debug --- components/esp8266/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/esp8266/CMakeLists.txt b/components/esp8266/CMakeLists.txt index 26120f438..887f9b6e6 100644 --- a/components/esp8266/CMakeLists.txt +++ b/components/esp8266/CMakeLists.txt @@ -69,7 +69,12 @@ else() target_link_libraries(${COMPONENT_LIB} PUBLIC "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib" "-lstdc++") target_compile_definitions(${COMPONENT_LIB} PUBLIC -DUSING_IBUS_FASTER_GET) if(NOT CONFIG_NO_BLOBS) - set(blobs "gcc" "hal" "core" "net80211" "phy" "rtc" "clk" "pp" "smartconfig" "ssc" "espnow") + set(blobs "gcc" "hal" "phy" "rtc" "clk" "smartconfig" "ssc") + if(CONFIG_ESP8266_WIFI_DEBUG_LOG_ENABLE) + list(APPEND blobs "core_dbg" "net80211_dbg" "pp_dbg" "espnow_dbg") + else() + list(APPEND blobs "core" "net80211" "pp" "espnow") + endif() foreach(blob ${blobs}) add_library(${blob} STATIC IMPORTED) set_property(TARGET ${blob} PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lib/lib${blob}.a) From 2115e024592ceb885b8a99818b1d98975dd060cb Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Mon, 9 May 2022 19:15:37 +0800 Subject: [PATCH 32/57] feat(bootloader): Disable CPU interrupt in boot --- components/bootloader/subproject/main/bootloader_start.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/bootloader/subproject/main/bootloader_start.c b/components/bootloader/subproject/main/bootloader_start.c index 3ba0addee..d79496db8 100644 --- a/components/bootloader/subproject/main/bootloader_start.c +++ b/components/bootloader/subproject/main/bootloader_start.c @@ -22,6 +22,7 @@ #include "esp_image_format.h" #include "esp_spi_flash.h" #include "esp_log.h" +#include "driver/soc.h" static const char* TAG = "boot"; @@ -30,6 +31,11 @@ static int selected_boot_partition(const bootloader_state_t *bs); void call_start_cpu(void) { + esp_irqflag_t irq; + + irq = soc_save_local_irq(); + ESP_LOGD(TAG, "CPU local irq: 0x%x", irq); + #ifdef CONFIG_BOOTLOADER_FAST_BOOT REG_SET_BIT(DPORT_CTL_REG, DPORT_CTL_DOUBLE_CLK); #endif From c7fcac9b45c00becbc7a0ad288c2c989543d19fc Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 13 May 2022 19:40:09 +0800 Subject: [PATCH 33/57] feat(bootloader): Boot close IRQ with level 3 --- components/esp8266/include/driver/soc.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/esp8266/include/driver/soc.h b/components/esp8266/include/driver/soc.h index ac3e330de..894f64e95 100644 --- a/components/esp8266/include/driver/soc.h +++ b/components/esp8266/include/driver/soc.h @@ -31,7 +31,11 @@ static inline esp_irqflag_t soc_save_local_irq(void) esp_irqflag_t flag; __asm__ __volatile__( +#ifdef BOOTLOADER_BUILD + "rsil %0, 3\n" +#else "rsil %0, 1\n" +#endif : "=a"(flag) : : "memory" From f88c2c56eab4bbcb0a26f3a27e89338107fbca19 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 21 Jun 2022 14:33:58 +0800 Subject: [PATCH 34/57] feat(spi_flash): Support Flash ID 0x164068 --- components/spi_flash/src/spi_flash.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/spi_flash/src/spi_flash.c b/components/spi_flash/src/spi_flash.c index 93240e9d2..221b25951 100644 --- a/components/spi_flash/src/spi_flash.c +++ b/components/spi_flash/src/spi_flash.c @@ -259,6 +259,12 @@ bool spi_flash_check_wr_protect(void) special_flash_write_status(0x01, status&(~(SPI_GD25Q32_FLASH_WRITE_PROTECT_STATUS)), 1, true); } } + } else if (flash_id == 0x164068) { + if(spi_flash_read_status(&status)==0) { //Read status Ok + if(status&SPI_GD25Q32_FLASH_WRITE_PROTECT_STATUS) { + special_flash_write_status(0x01, status&(~(SPI_GD25Q32_FLASH_WRITE_PROTECT_STATUS)), 1, true); + } + } } //Others else { @@ -435,6 +441,10 @@ void user_spi_flash_dio_to_qio_pre_init(void) to_qio = true; } //ENBALE FLASH QIO 0X01H+0X00+0X02 + } else if (flash_id == 0x164068) { + if (flash_gd25q32c_enable_QIO_mode() == true) { + to_qio = true; + } } else { if (spi_flash_enable_qmode_raw(&g_rom_flashchip) == ESP_OK) { to_qio = true; From 838197121a88bbe5cd6a2c9f9e334427a7116ab5 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Wed, 10 Aug 2022 16:04:45 +0800 Subject: [PATCH 35/57] feat(bootloader): add xmc spi_flash startup flow to improve reliability --- components/bootloader/Kconfig.projbuild | 9 + .../subproject/main/esp8266.bootloader.rom.ld | 3 +- .../include_priv/bootloader_flash.h | 21 +++ .../bootloader_support/src/bootloader_flash.c | 163 ++++++++++++++++-- .../bootloader_support/src/bootloader_init.c | 7 + 5 files changed, 192 insertions(+), 11 deletions(-) diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index 50c7633cf..2e108b512 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -174,6 +174,15 @@ config BOOTLOADER_STORE_OFFSET bootloader of the SDK's bootloader, you can set the option to store SDK's bootloader to other space in the flash instead of "0x0". +config BOOTLOADER_FLASH_XMC_SUPPORT + bool "Enable the support for flash chips of XMC (READ HELP FIRST)" + default y + help + Perform the startup flow recommended by XMC. Please consult XMC for the details of this flow. + XMC chips will be forbidden to be used, when this option is disabled. + + DON'T DISABLE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. + endmenu # Bootloader diff --git a/components/bootloader/subproject/main/esp8266.bootloader.rom.ld b/components/bootloader/subproject/main/esp8266.bootloader.rom.ld index 3ff8f2710..27d35bbee 100644 --- a/components/bootloader/subproject/main/esp8266.bootloader.rom.ld +++ b/components/bootloader/subproject/main/esp8266.bootloader.rom.ld @@ -8,4 +8,5 @@ PROVIDE ( gpio_input_get = 0x40004cf0 ); PROVIDE ( xthal_get_ccount = 0x4000dd38 ); PROVIDE ( uart_div_modify = 0x400039d8 ); -PROVIDE ( ets_io_vprintf = 0x40001f00 ); \ No newline at end of file +PROVIDE ( ets_io_vprintf = 0x40001f00 ); +PROVIDE ( ets_rom_delay_us = 0x40002ecc ); \ No newline at end of file diff --git a/components/bootloader_support/include_priv/bootloader_flash.h b/components/bootloader_support/include_priv/bootloader_flash.h index 763136e03..101a32752 100644 --- a/components/bootloader_support/include_priv/bootloader_flash.h +++ b/components/bootloader_support/include_priv/bootloader_flash.h @@ -22,6 +22,11 @@ #define FLASH_SECTOR_SIZE 0x1000 +#define CMD_RDSFDP 0x5A /* Read the SFDP of the flash */ +#define CMD_RDJEDECID 0x9F /* Read the JEDEC ID of the flash */ + +#define XMC_VENDOR_ID 0x20 + /* Provide a Flash API for bootloader_support code, that can be used from bootloader or app code. @@ -100,4 +105,20 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool */ esp_err_t bootloader_flash_erase_sector(size_t sector); +/** + * @brief Read the SFDP of the flash + * + * @param sfdp_addr Address of the parameter to read + * @param miso_byte_num Bytes to read + * @return The read SFDP, little endian, 4 bytes at most + */ +uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num); + +/** + * @brief Startup flow recommended by XMC. Call at startup before any erase/write operation. + * + * @return ESP_OK When startup successfully, otherwise ESP_FAIL (indiciating you should reboot before erase/write). + */ +esp_err_t bootloader_flash_xmc_startup(void); + #endif diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index f93226b3a..47edf2126 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -263,9 +263,13 @@ esp_err_t bootloader_flash_erase_sector(size_t sector) #include "esp_err.h" #include "esp_log.h" +#include "esp8266/rom_functions.h" #ifndef BOOTLOADER_BUILD #include "esp_spi_flash.h" +#else +#include "bootloader_flash.h" +#include "priv/esp_spi_flash_raw.h" #endif #ifdef CONFIG_SOC_FULL_ICACHE @@ -274,18 +278,11 @@ esp_err_t bootloader_flash_erase_sector(size_t sector) #define SOC_CACHE_SIZE 0 // 16KB #endif -extern void Cache_Read_Disable(); -extern void Cache_Read_Enable(uint8_t map, uint8_t p, uint8_t v); - -static const char *TAG = "bootloader_flash"; +#define XMC_SUPPORT CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT -typedef enum { SPI_FLASH_RESULT_OK = 0, - SPI_FLASH_RESULT_ERR = 1, - SPI_FLASH_RESULT_TIMEOUT = 2 } SpiFlashOpResult; +#define BYTESHIFT(VAR, IDX) (((VAR) >> ((IDX) * 8)) & 0xFF) -SpiFlashOpResult SPIRead(uint32_t addr, void *dst, uint32_t size); -SpiFlashOpResult SPIWrite(uint32_t addr, const uint8_t *src, uint32_t size); -SpiFlashOpResult SPIEraseSector(uint32_t sector_num); +static const char *TAG = "bootloader_flash"; static bool mapped; @@ -406,4 +403,150 @@ esp_err_t bootloader_flash_erase_sector(size_t sector) return ESP_OK; } +#ifdef BOOTLOADER_BUILD +uint32_t bootloader_read_flash_id(void) +{ + uint32_t id = spi_flash_get_id_raw(&g_rom_flashchip); + id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00); + return id; +} + +#if XMC_SUPPORT +static bool is_xmc_chip_strict(uint32_t rdid) +{ + uint32_t vendor_id = BYTESHIFT(rdid, 2); + uint32_t mfid = BYTESHIFT(rdid, 1); + uint32_t cpid = BYTESHIFT(rdid, 0); + + if (vendor_id != XMC_VENDOR_ID) { + return false; + } + + bool matched = false; + if (mfid == 0x40) { + if (cpid >= 0x13 && cpid <= 0x20) { + matched = true; + } + } else if (mfid == 0x41) { + if (cpid >= 0x17 && cpid <= 0x20) { + matched = true; + } + } else if (mfid == 0x50) { + if (cpid >= 0x15 && cpid <= 0x16) { + matched = true; + } + } + return matched; +} + +bool bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len) +{ + bool ret; + spi_cmd_t cmd; + + cmd.cmd = command; + cmd.cmd_len = 1; + cmd.addr = NULL; + cmd.addr_len = 0; + cmd.dummy_bits = 0; + cmd.data = NULL; + cmd.data_len = 0; + + ret = spi_user_cmd_raw(&g_rom_flashchip, SPI_TX, &cmd); + if (!ret) { + ESP_LOGE(TAG, "failed to write cmd=%02x", command); + } + + return ret; +} + +uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num) +{ + bool ret; + spi_cmd_t cmd; + uint32_t data = 0; + uint32_t addr = sfdp_addr << 8; + + cmd.cmd = CMD_RDSFDP; + cmd.cmd_len = 1; + cmd.addr = &addr; + cmd.addr_len = 3; + cmd.dummy_bits = 8; + cmd.data = &data; + cmd.data_len = miso_byte_num; + + ret = spi_user_cmd_raw(&g_rom_flashchip, SPI_RX, &cmd); + if (!ret) { + ESP_LOGE(TAG, "failed to read sfdp"); + } + + return data; +} + +esp_err_t bootloader_flash_xmc_startup(void) +{ + extern void ets_rom_delay_us(uint16_t us); + + uint32_t id = bootloader_read_flash_id(); + + // If the RDID value is a valid XMC one, may skip the flow + const bool fast_check = true; + if (fast_check && is_xmc_chip_strict(id)) { + ESP_LOGD(TAG, "XMC chip detected by RDID (%08X), skip.", id); + return ESP_OK; + } + + // Check the Manufacturer ID in SFDP registers (JEDEC standard). If not XMC chip, no need to run the flow + const int sfdp_mfid_addr = 0x10; + uint8_t mf_id = (bootloader_flash_read_sfdp(sfdp_mfid_addr, 1) & 0xff); + if (mf_id != XMC_VENDOR_ID) { + ESP_LOGD(TAG, "non-XMC chip detected by SFDP Read (%02X), skip.", mf_id); + return ESP_OK; + } + + ESP_LOGI(TAG, "XM25QHxxC startup flow"); + // Enter DPD + bootloader_execute_flash_command(0xB9, 0, 0, 0); + // Enter UDPD + bootloader_execute_flash_command(0x79, 0, 0, 0); + // Exit UDPD + bootloader_execute_flash_command(0xFF, 0, 0, 0); + // Delay tXUDPD + ets_rom_delay_us(2000); + // Release Power-down + bootloader_execute_flash_command(0xAB, 0, 0, 0); + ets_rom_delay_us(20); + // Read flash ID and check again + id = bootloader_read_flash_id(); + if (!is_xmc_chip_strict(id)) { + ESP_LOGE(TAG, "XMC flash startup fail"); + return ESP_FAIL; + } + + return ESP_OK; +} +#else +static bool is_xmc_chip(uint32_t rdid) +{ + uint32_t vendor_id = (rdid >> 16) &0xff; + + return vendor_id == XMC_VENDOR_ID; +} + +esp_err_t bootloader_flash_xmc_startup(void) +{ + uint32_t id = bootloader_read_flash_id(); + + if (is_xmc_chip(id)) { + ESP_LOGE(TAG, "XMC chip detected(%08X) while support disable.", id); + return ESP_FAIL; + } else { + ESP_LOGI(TAG, "flash chip is %08X", id); + } + + return ESP_OK; +} +#endif +#endif + #endif diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index fda2a49f7..2ca04d11f 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -642,6 +642,8 @@ esp_err_t bootloader_init() static esp_err_t bootloader_main() { + esp_err_t ret; + #ifdef CONFIG_BOOTLOADER_DISABLE_JTAG_IO /* Set GPIO 12-15 to be normal GPIO */ PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12); @@ -655,6 +657,11 @@ static esp_err_t bootloader_main() uart_console_configure(); + if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) { + ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!"); + return ESP_FAIL; + } + esp_image_header_t fhdr; if (bootloader_flash_read(ESP_BOOTLOADER_OFFSET, &fhdr, sizeof(esp_image_header_t), true) != ESP_OK) { ESP_LOGE(TAG, "failed to load bootloader header!"); From 81441d24054f1c839732da1eff5835bc7af22d12 Mon Sep 17 00:00:00 2001 From: Zhang Jun Hao Date: Tue, 13 Sep 2022 09:39:39 +0800 Subject: [PATCH 36/57] fix(lib): do not check basic rate for signal test router --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libnet80211.a | Bin 486240 -> 486252 bytes components/esp8266/lib/libnet80211_dbg.a | Bin 538088 -> 538108 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index 02e907255..a750e17a6 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,6 +1,6 @@ gwen: core: 231e0e2 - net80211: bde282f + net80211: d9d06fb pp: ec7ffb2 espnow: 231e0e2 diff --git a/components/esp8266/lib/libnet80211.a b/components/esp8266/lib/libnet80211.a index fc8e727e5868caaed9d12a02c06d393cdde30249..a1ed20ada7c5955e1bbf6a329d2e790689e85528 100755 GIT binary patch delta 6623 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 BduIRu delta 6310 zcmcgv4RBP|6~6breQ!6vJhBP-F@c3eHz*;Szs*KM*$hYtY{(CkUdKNP(&iVm08PfEX;Gv}ywOytnz?5Jkl9%sF?@ z-M8;M_x#_smY9<*F||>qBzuxQ&5@S2YJ}U9-$BSvrAOKbxk==?SueW5_jqpFNp4I5 z&&@MsZw2TF50UF4kMD!urW1M{#KM-50m)uYSZ_+V5Z0R}bP$$#K_^ewmmghsx(NHZ zbhV1GzU1-UAc7oy^U1T82wn8}St4|kr?+quzaNVr!u62ndLFvQGlnuku1QN~5yMX) zPrrxPzfBB3M%&*fh8v-yqluv}d3-ne%V+RUzZiMEFBgl>k{hOrtBH7{qIRaQ=w=x+W_zk!4gF6k(uB+K?8?#|*w*SrK&$ z(|;Qme4F+q0Nnqffqc>6eC0^UJ(QOx@6>+g>4mcLyx&}^3%g8%__lOWx!sgUmARo? zs1l!)M0u0VPbnN$Y|>uL_YeM1*$~~x_-!eZ_`Z}-nA#u(@f9g!`JIkPzS0rF&!vR& zSVstd!x7FmIL!Qh{4V4E)szt4g1=42z3&}<{GpWLyd3wI;_uCl;HY@JrOzk9(KXCK z>n15&S@ovE0@4!V<|W*h>PSg;^5Rt!q1nPr%G&+k7-3g6OM-^WRED87Oa}jUsY01~ zr^(i@;c-me*RQRWMW_F9%L1f?-zYgXYf6_GRRMe zvijC5(o!RzI)1wP+;-_*#De1el2yzX332k_nPynKUy|t`Ve5V=o1TCx+VUP`9grT7 ziz`aUEQ;@e(hsRF__cT{%?EFyTEASBC#c)r68E+u!~+`<;)^td0BU2Quyvy}h+3g( zBfh*Hf;Qo@3+8N+=0S9!;5QgiG`spBDKE}HVekcl+Rr5K$>8L2(WG3c*ka(-E;BUL zqg|(2S%}iSSPt_ZGgM}T7)j6P45!sLahQH~+8W9;s#A4KBm+Glh4NJ>R^#(-*t=0O z^OMzi5vc<>oG<)zh*DH@xsQTM@v8Zva_IS7S$CNz|gDEV^F~sF(vsDXckXu)?|kK}OwVwRHsBE~1}S#WE|#h8FwK9Lr=n z8$OO@*>pa{jlyLDJUWV%L?$Hk@kFmsxjKr4L*p^l?rRmkEG4438%yZYS>_8sli#FWouaXW^oHzVyR z(sPiJkH^0RtF&bde3H-RMa3s1C-k;{j~TRhRLhspst8{tpkj!@q`GTqRWMAovM}Df zcpBW*=gXol3b+Q<<)SIj5;j{A&b8gtuCprcQL! zKTp$a@j)vgZ}N+$tl&O_$3mlo^w>jli<(s^3=i^AXrj8ORA>o=fc5l2SlKSwRmT!x z!>ygDZEFQt92L}MiqJX~i&1=9M^CR4ob+>8Tqk5pFNYGcSmcMRM?hPh;6mFt2Cxk@ z%w~`IXpsR;Utpw#x6x;{S}})N#YLI}G$)5c{TvoZH^ap?8X1wAHn7DF$;nvdUDIM| zk$QZJ&^Pi`nkD2Ipv1&R^i(Ib{+RBRv_tTEYT>~z$m&yh!c!7m3PE=Z*|ZksXv+t% z6&ENhF`B?oAWWtcA*%rQYoM+`xTDix9~B5P&GDv>VK!RpX{>p6-CCnjq-`*6wqO%? z;O=NWiD8+xoea-v+n)-AywFwcWV#GK)^^KHgaqmjN5v=F`{cV%#MPW&5oRCLPE^0X z#C8l(ZS9ho!juk4RuB6N1;6T4I6V{Lhe1{*0_B?tsnvC@$rPO8859elag$_*k5HB- zj3h+yx;TA`kP(@f_zQSAA~G>)02lw9z`@r#k_L_(*nNhU_!uq&;_hbmsz=V!-(Y2c zPYSw%QnygiIn2k+@W44b4@R%+m1=tG7p@ZuLww%nR^>)vbuerjM$J5`Qs#TcTi{D= z^k{vWS>Q2@J=obURp~wg^pOjqu1X{yH^{R)CAvGUw; zDA zt*7Shex#+SMaBAj6`K;yV`j){M>URVnPn3PVV*?jYSgz=r)Wd5Ll-Y-qSZi1syDe@ z9W*B@KFL0S2~;eLclGJtfK_6~^Zq!zT=1hN$e|3`lcEWV9!EC0QIKINWwB~N0=sNf zzjrbkfw4hzv1vN6cZWlIE_REBkd=#V;xN={O9-6L)w)Ge->K0jcWY-EFHj$MOjM5+ z7!3xlR+?c?HIs3Iu<(P6?Y&BtHbrp%H=Msc^-IL(?IfW{isU2uoT&Ucw_O6a z6$j1HMz*e7*D5$@#9&|7X0Rxg1$lwg$=|s@n^y41dD(O|FGaqC{{{I-?pKmcC-b|J zm-CmA*YaCM7*BNK)M6 zEBt9RZ_3Q3vv|-H?QnCD*YmB&kMb+Xzvfv}v+-h8huqH3BcH*?xwGj~{;a#}K+SHM zzREv#+r(2i>EvjU&7-qqG(%jLO-w=$8oVAW$4wJ|6gN}Rjg4CKr)T-!QGUUnkma2{ zBgxt4w$c-KYU>>K+pvBySNkAK4}-C7I38*P0pLJT4=-WkfSnrizlw|v$DwKHN*3(y z3^`W|#{G22ZNc%aI*gE`dOp^+Femo)cUmwFRERvr^ecux>^UIy3~TD)1Jdtf`m6Do zv@}dLwo77RCx#^-!+I_xdq#%aJ$6H~cf(@EcUL4K-$yE{2>Cv;C6O}^>b=ew5$ zK-}ZftA|~K)J^Ufbvlkaug!J3qE$D}4Z~;r#~r0oW1RZ5D@v_*N0`&?mR=u+JJ{*K zV+ni+cX=|L7HBHgkJ2X0;SbYDhuv;lw$$YwyY!y1Q2Lpi3sZON6!@kAzm#9=Wk{dL zQ@XF(^W+FPT*&m=l6ia|*M=_QtBuqG83OWjP2j`ndDt#ywi*ekhQb6M8}IP+M}<6YtS3{o7mcDF+MzU_rVFJ)o8jV{ z^F_XuwBg5L=$pCuo457gDfIC?f!JZO`qt{Qcu$J;doef zhT6Hd@l*PuDY#Pw5>x1xP%1GiPt_CR3G7sz#60v~_&{P}*GJ22xyjMrCTOiPv+)q- zy;`o3jpfk!wVWfEx4`jFsa>5or4IflQM-0hVIL0+T5`<76z<~JOn5#C?Ya-5lhA^v zp;SNwG$nnjA$iH{olw`kVB4)TXsbuFR9UODvDm1f*8R7mo}ux zupYK&v9frNyFc&!p0R&sAdXhxX8e^2hUozLy`C6B(W#)8;vtKh> z=CaE8FlIbk&g!BxyN_+19@N>fA30tNm-b`4wZ!AO2<(d5{hnhyIEJXKY$Ze9Az{Nw7tY%Ni);gOcg$8Yi^y8o$E;Zm5tevOuop=&+ zpmeAd2PJ;ViyGaT*Y9^9*1=vMR%1b;R1Db-()ysDj)tHfYe0un_=->W^h#(y=+mLG zO&-+qRvf4mT1T7Q78;&jXlTGAG4QB7o54zj4T304jj;JsJf*t_G6hd*3CyVDcI}S$ z+aAe2hSB`Ezm2da^?cPm6u?8 z?T)GS3-lh^41Zmq&*$}cs@8%{X2T(?SdTH~?EhSOCa}a%%5t?GlUN&tHRot@4_kt$ z0x({d?V3A>IeUnzoQ8p(0#8rFKwpS_DS<#QAID^9o5nKvN}M|um`luK9-fP7pshOw z%k$XGcxOhhgxe=bxWnakIaNoImCD-Elk%mgUR-L}0O%vMrCst{!)P0f7=j(bmryHU zHVlr#V$}{y1(@Jf0VTjq2(d6nfDC^WPy}BI=!B{92qyT0fQ@h_K2YSM&3rf?IZ(vG z1}tna)656b#jwbXMZFWA5b!262v`H}3YY=k2#ACc2?*z5W&)2BMa-xytyqn9tdEDV zzku!P<&@}ZyfA47GeN{hED|mhvO`+S-K>%YW79haDfb7?HB{g=KZkK?fXTwX+BsN= zzQA!-fb;Wnkn?nm+}du=v*$7|)VTY`>5q|IoUUHIU0=U%F}XP1{UsMoS;^lqhtQg< zjrkp~AFLhQ%2Rr(gVKea$Wch@!oDLi0i!cOTuB%AVDxP2!eH>g*)ERN!P&b!_Vws| z9=jT%(yQT4=230kovcL)ZeUS9ZlDa4Z5SF=;yMd9;WtSwX(ez!CsDPVxNoDaF z&T%)c2yrx1O)I*M-m6_1Duu}#v*GhavH?C^Br7lh`w*xyVt!pxYJd(Si`1GeQnRGp zmmqcULq1&x4i`cNRJ#l!v|Y{{$Jr3= z@;2RH283$IvS|ps+o>UxVjQExH=!)xz&v+@|*z z{POhRYbw>eN|8LUlQ${Y1YCazFy~idFRvcK??yH0(Fc^(6{R5_#>q~P!yPE9jatLk z{Oy!bZ?(4)b(4o^-#B%z--9m)d!N^dEsOw!dYCVu3|!hUps-cETnB8{w>g zJQ%l0_b}$xrcF310=gNY6AA@n!FB=IAq!}O$y*Srv<+KyANBOF>uPlhzl?3NClI)e zIHY#iSF00;_^g0Nh~9=^hjHCdDqtZzB_I)+w&_gqnf8qEk*4847<6HpAHcWA?*Aod zpA6*}B`8n9f1*sxQAE2~fL&0Hc08Hq7=saDw_*LbERwmE+c7Iy0>)O^xQ7?uu%$Z$ N+i;9cK|~r~_J6nBMCmcNEVdZK<1_->Fl2V)zN&V#r6V&Jaj^d@pi;Jwrbdp_5W8(atuYec>b@b-LI z8D2tu6cWma(jO=|LX<%8_GI*4-;00x*}&_2`FHt5=_lAWzd`y9-ky!B8JuLw4cCz97uW3Tg{gN(C5^B8Xo zOXP!xCGdB{g82A|A$*?xcX4fui24;ZhT3InWDWa(@`TVa#;WMy%(^!z z*F!%to{4E@{F?L|`QOqb;O4n%Fkh8EfoEq#@rN_){6u;LAC(ctU&x5$&t!!21$eC^ z|A+K2{sG?m1@g{i4C3YKvAh&{%kX|%Mo4sGk|W@koZ+8ec)}CIjFtn>v%y)(;}<5E zWM-tNxj>)D@{Bh=_>XG5e0Wg=oxt}!9?spTbh?MnJmpkQF+!4f?9^~xf6ArAON10c z=n6HQAHk(pCFBlhW-Ok&PhS_661a8O&QNzoi8P~TsoyKz_ck4cYK&%1C{h1)1)Tt~ z%hh-)@tI2_p>VmXBWKZa)kD|7UO{$3@CtPaRGv|^^Ankg?>(E{{gpzUT=QU(O`mLj zw$!%$NT))ur9jn{&$9_}30X=)*f6*XdXu+~A?}coE|7 z`1Xc-?3sNy%1C%(a)6-#4V7oS*_f#q=boJ!>T^<|snayR$aE^D3Ly?lu|^k@d6Su@ z)FP{b7dM3S4%3AuBjoqIxgnkx?z+CueXRg#+tn7RuC@2cm(yf^uREOAxgC5)j+=j# zQ^o6YbY5BQFm8P9+aW%g^4`Xftc%FRErKI9&wk6URxLPxakY`}Y zX(gN|mFqn3z;#hsDSa432xcD7Vle@sYof0s7@y#d=ZoDsN~WV!`Fsb`87SGc)nVrG zYgv-w3xRRD41JD49SH?^soa5)t@ESrMnY9COH=N})OvXrW2U^D>!Epnd z9+jLN;H|FM7P7&iD5)bLMugGKq~X#Oit>f?IcPN@Tb(<}95X@+l6*2vaY(u%Q4CA? zW|$PA6GCut{x<=t9g>GmhW&!j2xNVf;`71i;4Mva5NljA_~91tR; zvP8Rbff@!K@5>=V8iyqfG@wYZTcD2wIxA3gWta3AjXKOIQ5}3ShUT1VOdM3HvP8wW z#f$7pTax+W0V!pi&odq8B%Q{t50;(EFT)90EgZ8xPj=Cx>mQOm?CRn017pKP=B)3K zg(osD;t8m?vAYBGY^r5X!c!_+>)Xz)q1En#nHmPdpD++o#D4hJ%&ZIh7wT51ky2Wk zi@RrxqI1pdo29_qv?>-qSD-^v4AsHiENi?z+in&=Exju73U?e&sLn^%){6oHn@iL% zv+$47gEqPhj&8$PuZQIANDe|Z68IuT)8OEC%%)t3-GTgCSh7PJ>l40d2ihth_U(|I z%4&bR+OQLuUqI+iWbQ)dIIGk^zF?<8v0xv=6yGR{BCUXC!6?NlImCJ{Ix!_FpcwTC z?Om}_u06n_R^;SmOXYU+-6Xj%Iv?L8d6cnZ z2{C|5EPTUeX=YSP%Fp4*l+->PX;rWOhDS<9Y9HZ|AhF5-^I*VDhVLa-1m5AY!cXS7 z%_n7yIiHzY6)XPsE57)qd^=|QRde=L%l*(nX0ozz!7#A;(3gtJ~g!9dq zbT5^tZjrp0!3#uPG1W5obGuv*XE8k?+Iy)v>JL;M#&|JVU(b}U@i}=zjjYrAA+!dQ zb!RLgTPz>v*T^pAwm2-RP|R33G~$}x2_M$T3o*J}7xA*ubb6UHKrO4ARK?KTVW?Ir zyi=kk^|Ky{N~6Q=0xcJ4+HS06EtR$q_^8r0*I#QdUah(;ku5ASD}#P;o4=0KQJs2W zW*v1Zrjw8+%M|r>)I}G7 zZ}4B`%=HTzXU+~~rT$KTa2Q6@KSZbB5Q$eqAv6-(fD?)ZiHGJ$hAv1=x`+#um#8a7p9b`%XIWUgh^LxOt@ zz7*WO$gQ>Jau`>G>~fe?gY2mhguHCc=Tw8Wf^&R0A;)|rE;Vpo?<#RtbvI+-)VScE%g)FJ7b zOYz{crL!g%iuGWbkfEX&Lrc1b4K1~=ie(MuQl=}3x9=Kl+%qE~a9R~I8lM$3sL&Y4 z!bHo}vE^3zCXB9W;!0mTcNnwgJRC|(`O*74^axKb^H7;rBOb-~BVNa2mw4zdz69|h zz7H|sp}+Rft9UWuDZCl+7EYJ?T*ci>b$S=hzfPsWCZ=8M;Do#w{xtHwMczc=4?I30 zvyp#;%!D99zUp*R48N}2snmuN@`>L^85e0oO1dk><$$9_$|z%g=KZ~$B~B?COniZ9 z#>A{(n~|4O7KEbgo$8^pdGIt3E#pOq8~Jv`?fk!pPxI+Fd*~3p32_qt5^({al;@$# z_}V-qTUP9+sRD_diJDe^SF5_y^E-R4dmkMp;Y zu@RN7_Uq^hI5&31p*5tH*0Hwe-eI_UE8BJj|2PN35T~l2qZ;BA=kE}Jg$}ExK+6Sc z5NNm8=71AkTkB<3O`Ixq(V6&5m@$iM9HN}-5cHm`o3FpZ9xL$WPN^LyhXb(Ej+4V+ z%-VJ<>09hLIeZLf?2^ZpIhv3KD!;Nk4oagWx78@2a)sJ;J{E}_O;fBow$0qXLVe|` z?v^wg8`Xz~@rs-c4&NF;4=k02H1Uq@=6`iFt0 zSgUI6ixpMlYC@`n<{RRWSqhZp73cEu^%8S9>jb*hX5Qi6N-O8-FRx^W2mF!WV?w99XAUg0Y zAmZe#K+#o*vIV+bpydKJATnpISKgW+~u$`Foo!?vVvxJVrPqPbKn+Y@v$#XC>3r}UZQIA2O>;YLD-+PbtCVAON z^QLw=wAP;?g=nLpu(D8bDmRTM#NF9WS_%~xp83ucDjsF&^@L Date: Mon, 19 Sep 2022 16:13:20 +0800 Subject: [PATCH 37/57] fix(spi_flash): Fix bootloader failed to read image data --- components/spi_flash/src/spi_flash_raw.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/spi_flash/src/spi_flash_raw.c b/components/spi_flash/src/spi_flash_raw.c index dee89962b..10abf29e0 100644 --- a/components/spi_flash/src/spi_flash_raw.c +++ b/components/spi_flash/src/spi_flash_raw.c @@ -39,7 +39,9 @@ uint32_t spi_flash_get_id_raw(esp_rom_spiflash_chip_t *chip) { uint32_t rdid = 0; +#ifndef BOOTLOADER_BUILD Cache_Read_Disable(); +#endif Wait_SPI_Idle(chip); @@ -49,7 +51,9 @@ uint32_t spi_flash_get_id_raw(esp_rom_spiflash_chip_t *chip) rdid = READ_PERI_REG(PERIPHS_SPI_FLASH_C0)&0xffffff; +#ifndef BOOTLOADER_BUILD Cache_Read_Enable_New(); +#endif return rdid; } @@ -150,8 +154,11 @@ bool spi_user_cmd_raw(esp_rom_spiflash_chip_t *chip, spi_cmd_dir_t mode, spi_cmd { int idx = 0; +#ifndef BOOTLOADER_BUILD // Cache Disable Cache_Read_Disable_2(); +#endif + //wait spi idle if((mode & SPI_RAW) == 0) { Wait_SPI_Idle(chip); @@ -272,8 +279,11 @@ bool spi_user_cmd_raw(esp_rom_spiflash_chip_t *chip, spi_cmd_dir_t mode, spi_cmd if((mode & SPI_RAW) == 0) { Wait_SPI_Idle(chip); } + +#ifndef BOOTLOADER_BUILD //enable icache Cache_Read_Enable_2(); +#endif return true; } From 64de58678e5ded75e02455524c97c0b2e10dcdfa Mon Sep 17 00:00:00 2001 From: Zhang Jun Hao Date: Sun, 9 Oct 2022 14:10:43 +0800 Subject: [PATCH 38/57] fix(lib): fix scan state error --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libnet80211.a | Bin 486252 -> 486256 bytes components/esp8266/lib/libnet80211_dbg.a | Bin 538108 -> 538112 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index a750e17a6..cd2d6c660 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,6 +1,6 @@ gwen: core: 231e0e2 - net80211: d9d06fb + net80211: 6d05180 pp: ec7ffb2 espnow: 231e0e2 diff --git a/components/esp8266/lib/libnet80211.a b/components/esp8266/lib/libnet80211.a index a1ed20ada7c5955e1bbf6a329d2e790689e85528..51748c5fb0c120bf63127c322fcdfcc5c134ca7a 100755 GIT binary patch delta 3221 zcmcJQT}%{L6vywqv%4(a;mbwVT2OXYv(T~%D<9hy(%r^jHE8|lgN>jV8wJ6yzLY)< zwkCa$G>e<&qz_t1Xwp<85}J%ju>ngfjTTu!Xq!f}Ep0W`3N$u0HEz$DogwhhP+FYi zKmT)obIzS}Z|=_C8O@m(%?Ur1RN@a5mldz+Qer|q#>ChR-K=F|fhBEdX8$PFd{~{! zr2nf^g-n{K)cF=jQ?+aXr7q-T%+lF3PpR`QSm1nh-W~t@2CVCXY%ZyDB|PTm>YN=u z-UigUx9D*;U{gB=m~Fngbe`G%qms72#%9Vnb6~`gF8h;_&T?z_)Aq?#=EoAw?hvl- zXUl%hGD+m%cvg4$rWbNd05>{puI~36KF&3Xo>JT5$({w;J{n$Xf<#U0=cCg#-3P~G zC(Oq*f!6p2UvqdC>G_4PmQ12iX9AM%@525ib#JaZw7RIY)cES-lrF9Q z9)B*y%+`C*`X2JP+$PfBTf0nv!z9|Hd{Lh_Jvz8m+_jn`JsW$I@@VpbRV!c2l2 zHDW0bL_(Xqd@Zy0yR~d;C?!{h+HOAVy>hb=F9d=)}gzGQ5ps1W?ycrRnJxj9;a^N(W=^{kC zvg5rMRfJMdlPJ1~Q=Ez-9!GH$aSE!?Xr3yJo#>Ra3tC&OUTvgFtXQ%8G=j`D#w_R; zjJO~Dh7rr?zZvoG=nsw9M{hw;Vo0gI=y@o<4{vzU ztB4cphv-S+QU?uGfKIVv58m)9MDaR3WFu%)MvP*I!M`&&brv&X+MZ$*r+vWd4;0lB zqu7C*It`$BJyX#ba~Vq@NU@_{$1KO-wES{Je1C#_4Ni<=hrvq>PWvCE{Dwq+z~ICv zb{IUwJ&Eq9U@a9iCJHKz0%Da~@&^KZJPhqu#LK)6Cdv9C^fg)`w32-SF|r9L8bq_h zQLT#dAsc``vOAD5geJr8A@K~~1<^y?32j3nogag)A>p;&u`+fua`Yu9 zOb}fHJc{&+4L3-q!6?!W*g|w1X=Y-IFyR4cC;T9ZvF9OXvt*{@WENaXFtIw83zL*k zY-cPvQCE0PpDuI_aWENAxc-u6qTfI((alI5F!_^|2^IIGG+b+pa5Z8@PtG02WIGfM zBW*@{AKG8XMI9!*7LF2b!t;GPfqMy`hbZ9{cs|nfInqavW`cVJX)#h+r?o^2;0Vzm z(v>8~q(o?TkknD{KoMEX~`<))AtW|1=+q_;Cn0(#lTYH2EDBE78ol;nJ6 z7HOH1{^~J__HL)856qGN|MAX&byn@bI@|sl6KnW)cw3ns4PLT+7&b@xOTycezF+h= D&+i+y delta 3181 zcmcJPe@t6d6vywquPxnLevC58229#+0VW+#7@&a&M8-C8#%(4fl!;+(OmJe{;*V@T zqFFSN7+gcnVj}Vf7^hQ4z`P}rrE%cYz%261ESZzYbQ&0puw+Z7^_;i&Nc)FDl-=Ze zzvq6=IX9=T?VB4lbG~> z)t14eWlCOdgEa4DD=2v-FJp$TBg>S$+=dmdmzO>9zaPL@UdWb`yi~z`&dWnb$%Y&PHAqQ5NR^D1HQc_{za zc%AqTPsR5X?s_CS44kU}G$jnwG`o_*K>Nod>%&0Hg^9(Mp2Jg8tY!&@O$D!@Yp;`WLq+U%QL-F6`Z#u$A z%?1G$ohW~$i$iIPr^CC&j8Q+S{Wwyx1g%vfY>0HB7r{@}Vm;6GmF!C8#o*W{F7X@6 z+&+ilmh+5A<>`C#_>pgWp>O=m}6FikiGJK(YL3j{oob*Z)ptKfb* z35N|{l=wPjp;pXEe1~%FpfDNvC1tun)LF7$VpxLu5`|MUGpY}jjdG%9P_&3s90fNQ zOm>)i+h|xrecQ3ghEBCrO7|<`v5n7sgmGLnV+QndTI@%^ti@LJKeTuj{k9gT<6U>P zI0iit&vZ{5#v8Oa0poP2{y^-JPiv(#ZW@Xo#0{4pMQy|=wrD&9V_u6JuJ2G(LyTgJ z#lLkto=q-_(?h{EkD_K`6kCwf>;))(2sd0d?K2Uh z*rM@u8mH$`h&lcoRWs(&I58K08XL4kww9nTqZpIC9yeUM8ZXvji^hvW>L0}%Z@>*# zsm6(wDv=)waPwy9928IR{cwxS4`oAW8PH007Os&^!`4e^1~@^M1Y=~mu<3iW3OGvE z4+CV^VQm1-49^C{gS-mf3kVl)f-eFh)p*^=*j3+TxeXd$Ga2A^Kv;Pk7>6PLGll1?NEkhEL?@ZT=nj`8&V7(g;t^! zNG&QYo<%wh*N9dkb*gmZh={>YwRHq9ItJBb#c+b`2z*A?3u9y{@F!UeY#PP>Ed183 zYXAOG>`#NEL<^B_QfV*I{V;$OubZKyc`g1~)MUmOCe2VZrcv&5?6AQxq#;Ee`Y}q) z4pL7%T%n!>yeUb&DQO&O0=UPK?nPRl);17rhT};28R#VQ!Vp^IR25_1NX8D}cVFup z{w0y0gX9TJoZZY=3_cV37j5@BrV{Z-@ce|>tiLpswh1v7p`X)+{1?QQMU#z0!P%j?})IHp#YEC)AgqoSc{L^yvtT?8@mb!zU0z;@@g4H!6+g druynos@(1{jW|PyUHSc@>D?BcD0uyR?B4>54lDow diff --git a/components/esp8266/lib/libnet80211_dbg.a b/components/esp8266/lib/libnet80211_dbg.a index ce152ab5f2ee7cb962a9a11df54e20886b22e23e..4e9215faecb66358ece0735211f23289ab3e7cfe 100755 GIT binary patch delta 3202 zcmcJQYitx%6vywqv(sJJN4MRw%a+pY&Qe>X&!weR*kEf*S_LXfkq?j*Bh?^Ckwr;> zEDwn$thKu05h$b>2nq<>G&qFts096>B1Rx6k0`MOj5R`Rzme2)rZc2tVw%-5$(jGT zzw7v zSojkx)rh6qVA)d3MloWexfzoeCsPc3{;4;OVoxmPiBq`vz*;7c5V4UA54j#2al(f? zKy2h&^e_jo#+v$=HPu+RmRbK}*pz-YJUqh}dYLg=DTdM78!Xr$i$M#QhcdVH1Gd48#RQ+RRvG*LY_pO>mT+JsB+Kh;m##lf^#xN%xdNyrfjHc4P^@XAnlQtsq*rLl7InU?2VRgUmQOHHUKA{@$BjLi`d!Oso$Fc$7)rJ(>n zOZm|GaB;zfvSWjl?>ihqY1|fZDuq?E7>hW2T#TO}-z+<0!6So?TqTqJHj^vWHl-x= zQ-)GKrik-ya>UP89~dm#J6Po6Nm>W@4HgJRu$Hige?}necsbu=bqIbCIzN|k)Pj#h zuZ2IQI(Lf}nO{(&AB#S_|7*sWzzB0Z;bFs|d@7teZSfVkaH(LdMnn!OM=_a=N^L!u zXQ7hk5_ARm1W3-59BS_o;hxe|Le+G}rlCHo=LP6|LC;@8ZPoL=sI)Wr3(=F%^HR(| z)bkw7_d>%}@l8WOM>K0aV!jejc+jP23u2Vpbxs5GSIEIwjqV{<1BBij0iCr*rzTi*U`GG|YDC zoEYVHoqwuxy3Nhxe{INrSm(qjx9j}a5YN?~%Zt>odZ^)q-azbxy6U<}lyMu#E~%0K z0!<{dVL!=n7$CU|b?GRDu$`n9Zjmg43O7m=wvxo*GKmH9GEfR&4T&4R%#fz=OK>kk z3h`zbmnr4T$uW%moG7dJK>HM{1r}yX4!rnMDz%Tr`>K`pWlC=T0USfh@4yX`W{^GT znc-k;y5_0%pr;v{kn**#futAqlc(Rwm`n5YlBX61sAz$SStyI34n=n3%dBXgH?zxhoSj#k)8v>vHLqvwde4VQ_|N1CV6EHBda zkmtpXI$;iq{B$<81RFdMr{eRlo9Ggx?!=NGvfzeSO6RNK52CRL-a;RG;}G#7jU%;a z+piy@?>wMzbDo?9=Y6MJG0@tzhp1ujF;SU2X^LYowc|W9odP~JG`(QbN(Z2 z7>|3qCouNCHr+|09dI5gz83=|mtdk_%1@gynXwjYA~&k=eXs(FJn3=9ZbHU7s|ODI zC6DO~d)+Ucv6{&7pmb=xL7;7&)u(RSBW=zwkoI8?B&CvhCbFDcZf`P?)-9ICt0r=N sv3v*&@)rKF9wriPx0|km8H~;_u delta 3098 zcmcJQeQZ-z6u|GjuV2uv`zW?_o22c)4cN-sYS+b;P++(j*+*~!$+oblizX;V=2vD? z=1hP%WzdAP2_r~Cwz-9^8QIfFbkp#M(dZBp0`dooMqOOYF!Bcpv7Xbux3qtlr8-`A z_B;1?&%N)w+wSe~yyO1wj@|;juiWSJ`zvCuSrHj!l07AyN13$Takha;{}vH-Vr+p) z|1&haie(y+Oc!Xnx3Fc5$Z~GRv@N3<27dmTFIvVmk&HXe;O2Kbn0ASXELHG;=OasY z_+T4|EPX@|vH^Xh={Kg&G&(z&{y&DnwZKxtk~&cGXv|=bj#X(VHW==>)t4o-c57@C zl@-5ORTFiewoX*l?S3RpjCZ`gC??#eyBXsg=T_uBG!eUJHl{%EMK zn3u}^?+dfwf5=0<;v=1I>!u=ay&qaY*dy5illPitYf)KHm|Qx}*iI1?{7QU^G4DB6 zUgY3kQl9)h>Mr@tGa0WqX)*~{{ky>|S7~4eW5KK`Gvl99-3}vT&at>@jVq7MaaYLT z+EjES*A-e(#`z^G==mZv6!)BumzjAC$A!#!AzmU}g0*`s{32C&O)nH%^d`Ya26Os^ zmey*3%=UbKhS>%2tA3)N6R9}iU$CbPs^OH(mi1`5Q zyeYn3SD+|rxdt^qfWPpfThSKeyb%0R*s?Y&iaOm4ZK!IuE2;q%<;E~3cs;3jYNS!g z>EWNoIZjWBSG(fLwZk-S7dfJ+J*X%*9;8CX-cvk1TQiP%Q$jOPJUPmZioc+EI?H`j z|4OocNb%$-H!41s^lK7_{~Rqilw2^WEFd>2zj{kVJzN7T%u+qS1$zlKFif}v_XzV) zn~f-ee!>=*BkY0797Gt75stzQ0)zFrh_&!0!31CBN*no1v}@7=hCC^UH-kM-D(0gQ zB52@6LJyoE^ui~EpJA5J3@a>%0C)(^u$RyQU4+{(Ojv-cge`E7z`(f*u?K1iCOAk4 zLqDM$rU|1kM<{{ZhY${^Bs>ajg#B=gupMHAci;x00k~BvhVU+}21>2cT7Cu^QD~pY zXUr6J)>@#~ichr*J|x?MHYeKl{i+-to;9AW@|9pO!5y0KTwGOd!&OHiWW#$TV1vU+ zbs|O0B-Jb`aVj7Fb{MSSSdAOB+((Yw~To^tnFGTy{z$Z>dIp`K;8RyEwx4 ze08HbO1xpiT=Q#}YGnN1^ZZS9l$gKWq8))$b7bhQRvx;m+r2N<%7xG953ExS;9YI< QaHqa?P*t+I$na<0Kb8df(*OVf From e2f55cbccad42f22d2da341dc13fa63e623233f6 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Thu, 16 Feb 2023 17:11:31 +0800 Subject: [PATCH 39/57] feat(spi_flash): Add patch to fix TH25Q16HB page 0 hardware issue --- components/esp8266/source/startup.c | 4 + components/spi_flash/CMakeLists.txt | 4 + components/spi_flash/Kconfig | 12 + components/spi_flash/component.mk | 4 + components/spi_flash/include/spi_flash.h | 9 + components/spi_flash/linker.lf | 1 + components/spi_flash/src/patch/th25q16hb.c | 709 +++++++++++++++++++++ 7 files changed, 743 insertions(+) create mode 100644 components/spi_flash/Kconfig create mode 100644 components/spi_flash/src/patch/th25q16hb.c diff --git a/components/esp8266/source/startup.c b/components/esp8266/source/startup.c index b9e582cec..42fc18825 100644 --- a/components/esp8266/source/startup.c +++ b/components/esp8266/source/startup.c @@ -93,6 +93,10 @@ static void user_init_entry(void *param) esp_set_cpu_freq(ESP_CPU_FREQ_160M); #endif +#ifdef CONFIG_ENABLE_TH25Q16HB_PATCH_0 + assert(th25q16hb_apply_patch_0() == 0); +#endif + app_main(); vTaskDelete(NULL); diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index b2a0f715c..255eff8e7 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -5,6 +5,10 @@ if(BOOTLOADER_BUILD) set(srcs "${srcs}" "port/port.c") set(priv_requires "bootloader_support") else() + if(CONFIG_ENABLE_TH25Q16HB_PATCH_0) + list(APPEND srcs "src/patch/th25q16hb.c") + endif() + set(priv_requires "esp8266" "freertos" "bootloader_support") endif() diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig new file mode 100644 index 000000000..3d97ba109 --- /dev/null +++ b/components/spi_flash/Kconfig @@ -0,0 +1,12 @@ +menu "SPI Flash" + + menu "Patch" + config ENABLE_TH25Q16HB_PATCH_0 + bool "Enable TH25Q16HB Patch 0" + default n + help + WARNING: If you don't use TH25Q16HB, you must not enable this option. + Although you use TH25Q16HB, you should ask your flash manufacturer + if your flash need use this patch. + endmenu +endmenu diff --git a/components/spi_flash/component.mk b/components/spi_flash/component.mk index f5eb97ca6..c4dfc940a 100644 --- a/components/spi_flash/component.mk +++ b/components/spi_flash/component.mk @@ -15,4 +15,8 @@ CFLAGS += -DPARTITION_QUEUE_HEADER=\"sys/queue.h\" ifdef IS_BOOTLOADER_BUILD COMPONENT_SRCDIRS += port COMPONENT_OBJS += port/port.o +else +ifdef CONFIG_ENABLE_TH25Q16HB_PATCH_0 +COMPONENT_SRCDIRS += src/patch +endif endif diff --git a/components/spi_flash/include/spi_flash.h b/components/spi_flash/include/spi_flash.h index d51756d72..7dfeb6a24 100644 --- a/components/spi_flash/include/spi_flash.h +++ b/components/spi_flash/include/spi_flash.h @@ -204,6 +204,15 @@ int esp_patition_table_init_data(void *partition_info); int esp_patition_copy_ota1_to_ota0(const void *partition_info); #endif +#ifdef CONFIG_ENABLE_TH25Q16HB_PATCH_0 +/** + * @brief Apply TH25Q16HB patch 0 to avoid some hardware issues. + * + * @return 0 if success or others if failed + */ +int th25q16hb_apply_patch_0(void); +#endif + #ifdef __cplusplus } #endif diff --git a/components/spi_flash/linker.lf b/components/spi_flash/linker.lf index 9ac365ea5..27695eb70 100644 --- a/components/spi_flash/linker.lf +++ b/components/spi_flash/linker.lf @@ -2,3 +2,4 @@ archive: libspi_flash.a entries: spi_flash_raw (noflash) + th25q16hb (noflash) diff --git a/components/spi_flash/src/patch/th25q16hb.c b/components/spi_flash/src/patch/th25q16hb.c new file mode 100644 index 000000000..425096f9b --- /dev/null +++ b/components/spi_flash/src/patch/th25q16hb.c @@ -0,0 +1,709 @@ +// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include "esp_log.h" +#include "esp_attr.h" +#include "spi_flash.h" +#include "priv/esp_spi_flash_raw.h" +#include "FreeRTOS.h" + +#include "esp8266/eagle_soc.h" +#include "esp8266/pin_mux_register.h" +#include "esp8266/spi_register.h" +#include "esp8266/spi_struct.h" + +#define SPI_FLASH SPI0 +#define SPI_BLOCK_SIZE 32 +#define ADDR_SHIFT_BITS 8 + +#if 0 +typedef int (*__ets_printf_t)(const char *fmt, ...); +#define ROM_PRINTF(_fmt, ...) ((__ets_printf_t)(0x400024cc))(_fmt, ##__VA_ARGS__) +#else +#define ROM_PRINTF(_fmt, ...) +#endif + +#define TOCHAR(_v) #_v +#define PRINT_STEP(_s) ROM_PRINTF("Step %d\n", (_s)); +#define JUMP_TO_STEP(_s) { ROM_PRINTF("Jump to " TOCHAR(_s) "\n"); goto _s; } +#define GOTO_FAILED(_s) { ROM_PRINTF("ERROR: " TOCHAR(_s) " failed\n"); ret = -EIO; JUMP_TO_STEP(step17); } + +#define write_u8_dummy(_c, _a, _d8,_d) {uint32_t __data = _d8; spi_trans(1, (_c), 8, (_a), 24, (uint8_t *)&__data, 1, (_d));} +#define write_u8(_c, _a, _d8) write_u8_dummy((_c), (_a), (_d8), 0) + +extern void Cache_Read_Disable_2(void); +extern void Cache_Read_Enable_2(); +extern void vPortEnterCritical(void); +extern void vPortExitCritical(void); +extern uint32_t spi_flash_get_id(void); + +static void delay(int ms) +{ + for (volatile int i = 0; i < ms; i++) { + for (volatile int j = 0; j < 7800; j++) { + } + } +} + +#if 0 +static void dump_hex(const uint8_t *ptr, int n) +{ + const uint8_t *s1 = ptr; + const int line_bytes = 16; + + ROM_PRINTF("\nHex:\n"); + for (int i = 0; i < n ; i += line_bytes) + { + int m = MIN(n - i, line_bytes); + + ROM_PRINTF("\t"); + for (int j = 0; j < m; j++) + { + ROM_PRINTF("%02x ", s1[i + j]); + } + + ROM_PRINTF("\n"); + } + + ROM_PRINTF("\n"); +} + +static void dump_hex_compare(const uint8_t *s1, const uint8_t *s2, int n) +{ + const int line_bytes = 16; + + ROM_PRINTF("\nHex:\n"); + for (int i = 0; i < n ; i += line_bytes) + { + int m = MIN(n - i, line_bytes); + + ROM_PRINTF("\t"); + for (int j = 0; j < m; j++) + { + ROM_PRINTF("%02x:%02x ", s1[i + j], s2[i + j]); + } + + ROM_PRINTF("\n"); + } + + ROM_PRINTF("\n"); +} +#endif + +typedef struct spi_state { + uint32_t io_mux_reg; + uint32_t spi_clk_reg; + uint32_t spi_ctrl_reg; + uint32_t spi_user_reg; +} spi_state_t; + +static void spi_enter(spi_state_t *state) +{ + vPortEnterCritical(); + Cache_Read_Disable_2(); + + Wait_SPI_Idle(&g_rom_flashchip); + + state->io_mux_reg = READ_PERI_REG(PERIPHS_IO_MUX_CONF_U); + state->spi_clk_reg = SPI_FLASH.clock.val; + state->spi_ctrl_reg = SPI_FLASH.ctrl.val; + state->spi_user_reg = SPI_FLASH.user.val; + + SPI_FLASH.user.usr_command = 1; + SPI_FLASH.user.flash_mode = 0; + SPI_FLASH.user.usr_miso_highpart = 0; + + CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_CONF_U, SPI0_CLK_EQU_SYS_CLK); + + SPI_FLASH.user.cs_setup = 1; + SPI_FLASH.user.cs_hold = 1; + SPI_FLASH.user.usr_mosi = 1; + + SPI_FLASH.user.usr_command = 1; + SPI_FLASH.user.flash_mode = 0; + + SPI_FLASH.ctrl.fread_qio = 0; + SPI_FLASH.ctrl.fread_dio = 0; + SPI_FLASH.ctrl.fread_quad = 0; + SPI_FLASH.ctrl.fread_dual = 0; + + SPI_FLASH.clock.val = 0; + SPI_FLASH.clock.clkcnt_l = 3; + SPI_FLASH.clock.clkcnt_h = 1; + SPI_FLASH.clock.clkcnt_n = 3; + + SPI_FLASH.ctrl.fastrd_mode = 1; + + while (SPI_FLASH.cmd.usr) { + ; + } +} + +static void spi_exit(spi_state_t *state) +{ + while (SPI_FLASH.cmd.usr) { + ; + } + + WRITE_PERI_REG(PERIPHS_IO_MUX_CONF_U, state->io_mux_reg); + + SPI_FLASH.ctrl.val = state->spi_ctrl_reg; + SPI_FLASH.clock.val = state->spi_clk_reg; + SPI_FLASH.user.val = state->spi_user_reg; + + Cache_Read_Enable_2(); + vPortExitCritical(); +} + +static void spi_trans_block(bool write_mode, + uint32_t cmd, + uint32_t cmd_bits, + uint32_t addr, + uint32_t addr_bits, + uint8_t *data, + uint32_t data_bytes, + uint32_t dummy_bits) +{ + if ((uint32_t)data & 0x3) { + ROM_PRINTF("ERROR: data=%p\n", data); + return; + } + + if (cmd_bits) { + SPI_FLASH.user.usr_command = 1; + SPI_FLASH.user2.usr_command_value = cmd; + SPI_FLASH.user2.usr_command_bitlen = cmd_bits - 1; + } else { + SPI_FLASH.user.usr_command = 0; + } + + if (addr_bits) { + SPI_FLASH.user.usr_addr = 1; + SPI_FLASH.addr = addr << ADDR_SHIFT_BITS; + SPI_FLASH.user1.usr_addr_bitlen = addr_bits - 1; + } else { + SPI_FLASH.user.usr_addr = 0; + } + + if (dummy_bits) { + SPI_FLASH.user.usr_dummy = 1; + SPI_FLASH.user1.usr_dummy_cyclelen = dummy_bits - 1; + } else { + SPI_FLASH.user.usr_dummy = 0; + } + + if (write_mode && data_bytes) { + int words = (data_bytes + 3) / 4; + uint32_t *p = (uint32_t *)data; + + SPI_FLASH.user.usr_mosi = 1; + SPI_FLASH.user.usr_miso = 0; + SPI_FLASH.user1.usr_mosi_bitlen = data_bytes * 8 - 1; + + for (int i = 0; i < words; i++) { + SPI_FLASH.data_buf[i] = p[i]; + } + } else if (!write_mode && data_bytes) { + int words = (data_bytes + 3) / 4; + + SPI_FLASH.user.usr_mosi = 0; + SPI_FLASH.user.usr_miso = 1; + SPI_FLASH.user1.usr_miso_bitlen = data_bytes * 8 - 1; + + for (int i = 0; i < words; i++) { + SPI_FLASH.data_buf[i] = 0; + } + } else { + SPI_FLASH.user.usr_mosi = 0; + SPI_FLASH.user.usr_miso = 0; + } + + SPI_FLASH.cmd.usr = 1; + while (SPI_FLASH.cmd.usr) { + ; + } + + if (!write_mode && data_bytes) { + int words = (data_bytes + 3) / 4; + uint32_t *p = (uint32_t *)data; + + for (int i = 0; i < words; i++) { + p[i] = SPI_FLASH.data_buf[i]; + } + } +} + +static void spi_trans(bool write_mode, + uint32_t cmd, + uint32_t cmd_bits, + uint32_t addr, + uint32_t addr_bits, + uint8_t *data, + uint32_t data_bytes, + uint32_t dummy_bits) + +{ + if (!data_bytes || data_bytes <= SPI_BLOCK_SIZE) { + return spi_trans_block(write_mode, cmd, cmd_bits, addr, + addr_bits, data, data_bytes, dummy_bits); + } + + for (int i = 0; i < data_bytes; i += SPI_BLOCK_SIZE) { + uint32_t n = MIN(SPI_BLOCK_SIZE, data_bytes - i); + + spi_trans_block(write_mode, cmd, cmd_bits, addr + i, + addr_bits, data + i, n, dummy_bits); + } +} + +static void write_cmd(uint32_t cmd) +{ + spi_trans(1, cmd, 8, 0, 0, NULL, 0, 0); +} + +static void write_buffer(uint32_t addr, uint8_t *buffer, int size) +{ + for (int i = 0; i < size; i += SPI_BLOCK_SIZE) { + int n = MIN(size - i, SPI_BLOCK_SIZE); + + write_cmd(0x6); + spi_trans(1, 0x42, 8, addr + i, 24, buffer + i, n, 0); + delay(3); + } +} + +static void read_buffer(uint32_t addr, uint8_t *buffer, int n) +{ + spi_trans(0, 0x48, 8, addr, 24, buffer, n, 8); +} + +static void erase_sector(uint32_t addr) +{ + write_cmd(0x6); + spi_trans(1, 0x44, 8, addr, 24, NULL, 0, 0); + delay(8); +} + +int th25q16hb_apply_patch_0(void) +{ + int ret = 0; + uint32_t flash_id; + int count; + spi_state_t state; + uint8_t *buffer256_0; + uint8_t *buffer256_1; + uint8_t *buffer256_2; + uint8_t *buffer1024; + + flash_id = spi_flash_get_id(); + if (flash_id != 0x1560eb) { + ROM_PRINTF("WARN: id=0x%x, is not TH25Q16HB\n", flash_id); + return 0; + } + + buffer1024 = heap_caps_malloc(1024, MALLOC_CAP_8BIT); + if (!buffer1024) { + return -ENOMEM; + } + + buffer256_0 = buffer1024; + buffer256_1 = buffer1024 + 256; + buffer256_2 = buffer1024 + 512; + + spi_enter(&state); + + // Step 1 + PRINT_STEP(1); + write_cmd(0x33); + + // Step 2 + PRINT_STEP(2); + write_cmd(0xcc); + + // Step 3 + PRINT_STEP(3); + write_cmd(0xaa); + + // Step 4 + PRINT_STEP(4); + write_u8(0xfa, 0x1200d, 0x3); + write_u8_dummy(0xfa, 0x2200d, 0x3, 1); + + // Step 5-1 + PRINT_STEP(5); + read_buffer(0xbed, buffer256_0, 3); + if (buffer256_0[0] == 0xff && + buffer256_0[1] == 0xff && + buffer256_0[2] == 0xff) { + ROM_PRINTF("INFO: check done 0\n"); + } else if (buffer256_0[0] == 0x55 && + buffer256_0[1] == 0xff && + buffer256_0[2] == 0xff) { + JUMP_TO_STEP(step10); + } else if (buffer256_0[0] == 0x55 && + buffer256_0[1] == 0x55 && + buffer256_0[2] == 0xff) { + JUMP_TO_STEP(step14); + } else if (buffer256_0[0] == 0x55 && + buffer256_0[1] == 0x55 && + buffer256_0[2] == 0x55) { + JUMP_TO_STEP(step17); + } else { + ROM_PRINTF("ERROR: 0xbed=0x%x 0xbee=0x%x 0xbef=0x%x\n", + buffer256_0[0], buffer256_0[1], buffer256_0[2]); + GOTO_FAILED(5-1); + } + + // Step 5-2 + read_buffer(0x50d, buffer256_0, 1); + buffer256_0[0] &= 0x7f; + if (buffer256_0[0] == 0x7c) { + JUMP_TO_STEP(step17); + } else if (buffer256_0[0] == 0x3c) { + ROM_PRINTF("INFO: check done 1\n"); + } else { + ROM_PRINTF("ERROR: 0x50d=0x%x\n", buffer256_0[0]); + GOTO_FAILED(5-2); + } + + // Step 6 + PRINT_STEP(6); + for (count = 0; count < 3; count++) { + erase_sector(0); + + bool check_done = true; + read_buffer(0x0, buffer1024, 1024); + for (int i = 0; i < 1024; i++) { + if (buffer1024[i] != 0xff) { + check_done = false; + ROM_PRINTF("ERROR: buffer1024[%d]=0x%x\n", i, buffer1024[i]); + break; + } + } + + if (check_done) { + break; + } + } + if (count >= 3) { + GOTO_FAILED(6) + } + + // Step 7-1.1 + PRINT_STEP(7); + read_buffer(0x400, buffer256_0, 256); + read_buffer(0x400, buffer256_1, 256); + read_buffer(0x400, buffer256_2, 256); + if (memcmp(buffer256_0, buffer256_1, 256) || + memcmp(buffer256_0, buffer256_2, 256)) { + GOTO_FAILED(7-1.1); + } + + write_buffer(0, buffer256_0, 256); + write_buffer(0x200, buffer256_0, 256); + + // Step 7-1.2 + for (count = 0; count < 3; count++) { + read_buffer(0, buffer256_1, 256); + if (memcmp(buffer256_0, buffer256_1, 256)) { + break; + } + + read_buffer(0x200, buffer256_1, 256); + if (memcmp(buffer256_0, buffer256_1, 256)) { + break; + } + } + if (count < 3) { + GOTO_FAILED(7-1.2); + } + + // Step 7-2.1 + read_buffer(0x500, buffer256_0, 256); + read_buffer(0x500, buffer256_1, 256); + read_buffer(0x500, buffer256_2, 256); + if (memcmp(buffer256_0, buffer256_1, 256) || + memcmp(buffer256_0, buffer256_2, 256)) { + GOTO_FAILED(7-2.1); + } + write_buffer(0x100, buffer256_0, 256); + write_buffer(0x300, buffer256_0, 256); + + // Step 7-2.2 + for (count = 0; count < 3; count++) { + read_buffer(0x100, buffer256_1, 256); + if (memcmp(buffer256_0, buffer256_1, 256)) { + break; + } + read_buffer(0x300, buffer256_1, 256); + if (memcmp(buffer256_0, buffer256_1, 256)) { + break; + } + } + if (count < 3) { + GOTO_FAILED(7-2.2); + } + + // Step 8 + PRINT_STEP(8); + read_buffer(0x0, buffer256_0, 1); + read_buffer(0x23, buffer256_1, 1); + if (buffer256_0[0] != 0x13 || buffer256_1[0] != 0x14) { + ROM_PRINTF("ERROR: 0x0=0x%x 0x23=0x%x\n", buffer256_0[0], buffer256_1[0]); + GOTO_FAILED(8); + } + + // Step 9-1 + PRINT_STEP(9); + read_buffer(0x140, buffer256_0, 2); + if (buffer256_0[0] != 0 || buffer256_0[1] != 0xff) { + ROM_PRINTF("ERROR: 0x140=0x%x 0x141=0x%x\n", buffer256_0[0], buffer256_0[1]); + GOTO_FAILED(9-1); + } + + // Step 9-2 + buffer256_0[0] = 0x55; + write_buffer(0xaed, buffer256_0, 1); + write_buffer(0xbed, buffer256_0, 1); + for (count = 0; count < 3; count++) { + read_buffer(0xaed, buffer256_0, 1); + if (buffer256_0[0] != 0x55) { + break; + } + + read_buffer(0xbed, buffer256_0, 1); + if (buffer256_0[0] != 0x55) { + break; + } + } + if (count < 3) { + GOTO_FAILED(9-2); + } + +step10: + // Step 10-1 + PRINT_STEP(10); + for (count = 0; count < 3; count++) { + erase_sector(0x400); + + bool check_done = true; + read_buffer(0x400, buffer1024, 1024); + for (int i = 0; i < 1024; i++) { + if (buffer1024[i] != 0xff) { + check_done = false; + ROM_PRINTF("ERROR: buffer1024[%d]=0x%x\n", i, buffer1024[i]); + break; + } + } + + if (check_done) { + break; + } + } + if (count >= 3) { + GOTO_FAILED(10-1); + } + + // Step 10-3.1 + read_buffer(0, buffer256_0, 256); + read_buffer(0, buffer256_1, 256); + read_buffer(0, buffer256_2, 256); + if (memcmp(buffer256_0, buffer256_1, 256) || + memcmp(buffer256_0, buffer256_2, 256)) { + GOTO_FAILED(10-3.1); + } + write_buffer(0x400, buffer256_0, 256); + write_buffer(0x600, buffer256_0, 256); + + // Step 10-3.2 + for (count = 0; count < 3; count++) { + read_buffer(0x400, buffer256_1, 256); + if (memcmp(buffer256_0, buffer256_1, 256)) { + break; + } + + read_buffer(0x600, buffer256_1, 256); + if (memcmp(buffer256_0, buffer256_1, 256)) { + break; + } + } + if (count < 3) { + GOTO_FAILED(10-3.2); + } + + // Step 10-3.3 + read_buffer(0x100, buffer256_0, 256); + read_buffer(0x100, buffer256_1, 256); + read_buffer(0x100, buffer256_2, 256); + if (memcmp(buffer256_0, buffer256_1, 256) || + memcmp(buffer256_0, buffer256_2, 256)) { + GOTO_FAILED(10-3.3); + } + buffer256_0[9] = 0x79; + buffer256_0[13] = (buffer256_0[13] & 0x3f) | + ((~buffer256_0[13]) & 0x80) | + 0x40; + write_buffer(0x500, buffer256_0, 256); + write_buffer(0x700, buffer256_0, 256); + + // Step 10-3.4 + for (count = 0; count < 3; count++) { + read_buffer(0x500, buffer256_1, 256); + if (memcmp(buffer256_0, buffer256_1, 256)) { + break; + } + + read_buffer(0x700, buffer256_1, 256); + if (memcmp(buffer256_0, buffer256_1, 256)) { + break; + } + } + if (count < 3) { + GOTO_FAILED(10-3.4); + } + + // Step11-1 + PRINT_STEP(11); + + for (count = 0; count < 3; count++) { + read_buffer(0x400, buffer256_0, 1); + read_buffer(0x423, buffer256_1, 1); + if (buffer256_0[0] != 0x13 || buffer256_1[0] != 0x14) { + ROM_PRINTF("ERROR: 0x400=0x%x 0x423=0x%x\n", buffer256_0[0], buffer256_1[0]); + break; + } + } + if (count < 3) { + GOTO_FAILED(11-1); + } + + // Step11-2.1 + for (count = 0; count < 3; count++) { + read_buffer(0x540, buffer256_0, 2); + if (buffer256_0[0] != 0 || buffer256_0[1] != 0xff) { + ROM_PRINTF("ERROR: 0x540=0x%x 0x541=0x%x\n", buffer256_0[0], buffer256_0[1]); + break; + } + } + if (count < 3) { + GOTO_FAILED(11-2); + } + + // Step11-2.2 + for (count = 0; count < 3; count++) { + read_buffer(0x50d, buffer256_0, 1); + buffer256_0[0] &= 0x7f; + if (buffer256_0[0] != 0x7c) { + ROM_PRINTF("ERROR: 0x50d=0x%x\n", buffer256_0[0]); + break; + } + } + if (count < 3) { + GOTO_FAILED(11-2); + } + + // Step 12 + PRINT_STEP(12); + buffer256_0[0] = 0x55; + write_buffer(0xaee, buffer256_0, 1); + write_buffer(0xbee, buffer256_0, 1); + + // Step 13 + PRINT_STEP(13); + for (count = 0; count < 3; count++) { + read_buffer(0xaee, buffer256_0, 1); + if (buffer256_0[0] != 0x55) { + break; + } + + read_buffer(0xbee, buffer256_0, 1); + if (buffer256_0[0] != 0x55) { + break; + } + } + if (count < 3) { + GOTO_FAILED(13); + } + +step14: + // Step 14 + PRINT_STEP(14); + for (count = 0; count < 3; count++) { + erase_sector(0); + + bool check_done = true; + read_buffer(0x0, buffer1024, 1024); + for (int i = 0; i < 1024; i++) { + if (buffer1024[i] != 0xff) { + check_done = false; + ROM_PRINTF("ERROR: buffer1024[%d]=0x%x\n", i, buffer1024[i]); + break; + } + } + + if (check_done) { + break; + } + } + if (count >= 3) { + GOTO_FAILED(14); + } + + // Step 15 + PRINT_STEP(15); + buffer256_0[0] = 0x55; + write_buffer(0xaef, buffer256_0, 1); + write_buffer(0xbef, buffer256_0, 1); + + // Step 16 + PRINT_STEP(16); + for (count = 0; count < 3; count++) { + read_buffer(0xaef, buffer256_0, 1); + if (buffer256_0[0] != 0x55) { + break; + } + + read_buffer(0xbef, buffer256_0, 1); + if (buffer256_0[0] != 0x55) { + break; + } + } + if (count < 3) { + GOTO_FAILED(16); + } + +step17: + // Step 17 + PRINT_STEP(17); + write_cmd(0x55); + + // Step 18 + PRINT_STEP(18); + write_cmd(0x88); + + spi_exit(&state); + + heap_caps_free(buffer1024); + + if (!ret) { + ROM_PRINTF("INFO: Patch for TH25Q16HB is done\n"); + } + + return ret; +} From a22a955007efe8c8b87a09ce845adc186d05d9fd Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Thu, 23 Mar 2023 19:40:40 +0800 Subject: [PATCH 40/57] change addr3 to broadcast for ESPNOW Closes https://github.com/espressif/esp-now/issues/57 --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libnet80211.a | Bin 486256 -> 485304 bytes components/esp8266/lib/libnet80211_dbg.a | Bin 538112 -> 544204 bytes 3 files changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 components/esp8266/lib/libnet80211.a mode change 100755 => 100644 components/esp8266/lib/libnet80211_dbg.a diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index cd2d6c660..e5ab12238 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,6 +1,6 @@ gwen: core: 231e0e2 - net80211: 6d05180 + net80211: 7b39142 pp: ec7ffb2 espnow: 231e0e2 diff --git a/components/esp8266/lib/libnet80211.a b/components/esp8266/lib/libnet80211.a old mode 100755 new mode 100644 index 51748c5fb0c120bf63127c322fcdfcc5c134ca7a..7739a55f39cf04a0f9f6f9b8b826717595447900 GIT binary patch literal 485304 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≶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

l5YafV4-X- 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

@rHfHGdp0RDw{A1C)W6=qB4gKlR_UnwQRCDx{ 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 diff --git a/components/esp8266/lib/libnet80211_dbg.a b/components/esp8266/lib/libnet80211_dbg.a old mode 100755 new mode 100644 index 4e9215faecb66358ece0735211f23289ab3e7cfe..db24dcc67690e6d114aee94261e7555e162ce4b5 GIT binary patch literal 544204 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

ZlCP|ukQt)KSK2rgbKr zV~!qxM(F>3vFDa51>1`!kha3DcnR!Z{{sZ+Vn(B{JeI?@}j4(o`~kdR#g)E`4QOx;!qu2x%_s zH7GX)`)s_w#|r)59hZJEF8wQ{S%2=mrC|HEL(*PD%JcYvR%m#HBYPO%(&jpX~t7n|(I$e~{)P z<Bm+>u{D)nf0?CMZ+%|cY8zN&X$cHtLjnsCLbX;E2ibB+FxjJe2E z(b7^;Rp%^N#LwB(G~*&vOKqcf#YwJGna|6Z3sz=J}pwMRhg5np0ox z;QKpOO*eVk=9>8nFk{{XQ&?Snb#)CcbkWi%_+~K7e_8e7=8Beje2cbA+f=bAPRl~f z)iE!>eCfwzkdo9?^_3rE(bQanuYKb)IcQ|u;e_vfGit1w-{cipxwyWe+DtBMsK=6H zCVZ^c;mkMJv@C9JEUQ~Ezs6YL!3)vjyF$2g5Rcbi@7!2eb3@sTnwHWfB?}trt8Q|d z=9@)|OL%BCekKU_ax}J>i+mY9qhEp@#7r+PrF*U%o{J1T3g zXq;DLyqODyTt2a4E1FwkON)z&^HNc@aB+RJ)Y*O^sH@SdYZgs3Erhu*V+C7oYQpXP zOnDy|@)n?@`qa(d>jg|>V!_8Ah>F#AaTDHvR>S(zll0n|Gp01QG*4yIc^@e96jwEx z)-*+8an{y1u+3{=#h!(w6)V8IZL@h%<0(4a(-!MU#+B`FoTqLI6wrWMKNpF%#<{w> z=7yQ|^RKL}#lrNwcm-9~RN%%pRhD_+2FugCSI4PpTvFCtg>*$T)+eUW@yoo{k!jKp z&FKHuTvWW3uBL2$4eq_GGLuBlPf;;*ELk>xK{FOPbX*^rJ!|RzNc}G!V>U;c_KZme z#ya;J{6W$YtUjcedy4M4_=E6_i?!jHZkhWT?s@owa7=aQ7&K$8s}7x9IjowF$#(nC zBNsBq%=SB1_y)uig;|Hog)_nY=7`N(F3h~kgjp`nG}4Awk{2P6 zS0lbfaTeJ9D*hlV5okjlIUxG`L{FbNV0SM5ApeCxd+Nvm(f>&Fw9f^**WwSd34!+1 zkprUND*C;M+Z9g$+q!XInR%%r+q%6i`V}baec{&-9}{LBxZljYY~#}qEayRQ{qt%F z_0*BA|Iwo7m9zx8PIX~3jjhKPV zy09O(vY(VdE_0j%h$&=B7$KDtA?XO@nTUD3L*}F+VfqUqxaIhRWFXLnI&z>Ke-NIr zralkxKm@k}e~>%`>Zv0KM4t+FEAa=p0)aNvkprUVs!Kh~NkZVdjHI`Y^YomEUB}Nv znr93t;}FQS=T#IkeVBQv20$)Bpq@H%K=ebvwk%Umv@6BTm$31}ia~7M$Slu}MNHeV zh^F>CT0HAaX1=coGv8!k`sOhoZCK_sVb+CbQK)Afxt@?`BhFWx2Dbf{XQ60A9ohCV zuDaAWBMu?BwfKWnAy6L@4v0P-X?Gs}APoq#p^h97J2D1$NOFZ>}m6oviX}Z>-d^5>zD*P`lp{k z!b8A=g=v!^%&Wu&!n8NrFXUx=@Qx1pp?wI!E{jGm_0*9A3-AZI5rO)zBfeQU8$NCm z=KOtE_8S*{?{ZK~^h&~7Ga$!RLgFqYV$N|xFUx|8i*NiZ)M)p&j3wv9i zb3{)a+16*A=(&BnPd4k7mut6uIVvFR2X_2qAGPBrr@7hu z_udi6Z)i}=I1eraPeq`f`DO~!-&|ot=Bzhuz60huZ~fdN%)EC9GcWCE!*$^vVODjR zFntVHJW7~#DH7)PXS(ou#9UqJle|QjeYsVb`W1>(!FCzlD|+h4wmoxbvk-p}_7yk9 zpttXRgU1=v%l<%!EH-ImEE~!Y1gkgYa)uzBf4f}RE_S)Fz3hGkuxkwG{O}tZoX%>I zna{K{n6e6idirL6B0qxohf4pjFvl29qYc}ClQ8S}xG?L!MVRws)*})*qqNk1=fPM&gHiFAe2U#OF)R6M>{4j)BzJ{T%kWRIUh+d<1eU;zD8OYZiV6F^i!MxBn}Y{sG}1A^y2=65>t5tXI46 zi-wH-$MLX5E3$2dP7_$C#_d zhB~r6##|?Q+Or?H+!277?Kq67BL_sE2Daazcpl99Q%4S<57Z$x^XLK~W*ME~G27RU zjnvq&k@-^xQ-del5XiL67G~S#2-Dxi!YpTma53UBiaDRQe-?`Hu->lK1U90DZQLp65$;3v)j9 z35O8BA)Jo*En&97VPUq-abeC*ANXP&C;{Odu-T7-J{LRz!TkpQARNwUPaQcRdehIL ze-^qt1bdwIEimn=BirMwLa>+p-m0`AiqbT4Rz#z=>H`8M_w%N49-+Hf`>}AEXn3{;4AeM4u#W z%VjqgdOPNu?KSMFBik{*oHpzXkc%a6xv=g3L8M(SLNv7zkOVOAaY zENW3cf?ZEdS)w=dm1#`8`GQZ1nXfq>^WTn9SAkPy`%)>)d8rd-z8i$;`zB$Qxm1{S zStCsQ9}2U+W}St9+WbQFTM%y(W?SwPeh=|S!gXkqPlZE>9WF=sVLO@q5b#Xs%)SSh zZE5z|z|708N&6Lu8x^x@Y@g(6KpX1Fwol$A`pt+}3I7D~I>lLF>*rz7Q%AObn4kVR zuV$M9{u_9g=*fE&Gfn&Bh;tC^n9O#eo;tGK9(^MEy@<_N1RI{4~$XJgJ?!-hI?K=fCGSr*HjN_(kKrRb?6+j`QQ-Nq$=Q`y->y6MmMlzkAT ze%W#G!}VB?xqgR)ha>h24@NvdcnD%t%j8W$%(Tmu1`nW$X=TIx_Bi4N@_MGi> zC{jb7*7PgzlSuAEpq}$_RM>}kHR}uX^!;zqv&=KtCeYK~EF&=26^=F3(|)Wl?H3B~ zMr@92U_)LZdfv7D9bxLtzBFv8UnhFLmw<-)AzH-ra* z?-Wi2^F9dHneEC&=&ryY#H`mLPe%@j-i%k!^L`0LUFT|+gXxDlvOQOm4tBYLg{(%P z4Rz#z=x8P`JERtFNpbV7|V+k^IjjT z&qaQh8x6=$L{A+#Ao>YNyXE+U@H;KcOC32-4uIq#xD_O{kJ#i1+i|iGX?G?5Ab%7a z>c|1noBqs!3KBx#KE};xpEPn9e-N%qmQ%^HZ@_iW?i&Qj$VW*+u=WXLJ$5amg||+n zMm+v2A~J0c3G*p|2>ek$4Kc@mGS3IxE&NZ|JS+Sc@CU+tnt@L`(4KWM;|Z8`Ou#hi z`J@8v$efP>!kjFqZ?r zwL^Q(`|HA-#|%ufW6rH$+E7QfV~*Jmfu8#wW?TZV1Ah;J_VkkpcE5u^$O8z}Q%4Sn zo@17^-zd!ecQbB?%{I|fN49yN6+P|EK8%#RSM*%Ye-UPV-WEQL_)D_9h9f>(_yxo{ znC5;Le~|M_A^UUC4@RefEvPy+lA?Et#uA)cpJTvE)I&;oh^xPk! zp37narrA2&E_&+7whno;k-Xc)hB|UU^qe31d>QdB;kV(xka-v353*PE)RFBu{MSX# ze*LE6_k=6qrxd1C%H{&7dFdFt|JQSX)@{Z&*=&2*yyyuI)6!Cb)B`Pn! zqs6?`k!{{u(eo*y>xKCg(M;xDfIr9`qNk2*ucypL+S>5`LHehTY;ES!rXGKgN5qCY zvfXxw|zqH_=$AWr+Z4X{$d$WsB%XbbV6hq zOVh}lDaa56dwxEZyp~$oKg2QGGH?eP`ov#4X_Mf8XlPev< zeNjKYhlTb*#AgaG!?xi(Vdgda>aeMVu155HGUhH}*6Sz2L9p4T!~PxUwkR8}11zf$ z?fO?`pT;(ao=+N?aaC;EL_ZKdd2cLj*fzU`*=AZ}uH zSsR4eR)0X6dAY59MfeTGuM2ZIz9W1D@d;u2NtJd!3-K7?9K_ke^q&JeyN$TQ+CWFP z;p8bIJ;qgL?Fvl%3PC~y4{7uobkC97e&u~fxifc;4_bTWxK{cO8?Z6?fkwkde)(k_96U1 z%&`gQMK}=h#^C<2qaXI+VoY~o?HTtCdQlJNJ$p86ju=Kd4w%yRcD=JtvDcM)@2Xl>pT<`aG&DmL2!Y0s0Q zr;cpf(lqNk2*^Ioj%Ckk_H z;P>$t-=A(FGJd0k3Yy2VnZD{Ao>+Z+x>yLVnZF-?hmY_&Hea; zTrW1%kprT?S@ay&TNN+2_K3f&^lOE=-T1!JuYzCOKED?|b!6K%o4RvJO&J#q> zCvi8>UdD%F(NjmZ>**EB{yJekxyydcK6426cL?)o-ACz@2QiRuiJm%gK=coYp4-v~ zh3hb`Q@UM0MO#n?BDk=l3_)-c4LTw6X&z^glRVBM_w_iJe7eVZL{6pFTW8$C9=9TLSwYAO1be+~6?rJN-f^It=5ZS$SI%KR zN)F)3GOJ>l*(_%%o}jo`@l3_#iW?L!QM^pC znO|&UDC~~5Tr-cNe?sZo$+E0>Dc+~}EyYI_pH!TLK4krH|H}3m9*bJeRLt{iR?l-9 zwqKPfo~xLB)Y@?W%J#ih#VZxBQ_OQ~wtsTp$uf^gE$>v!{WjZ&4=6sYnEOxGCIRhg z`}sh{X^JxxbDzhq3werpoM`ntw`RGTEbB{?;-!jLC|;|$jV$ZeM#WndKdYGgL)Lyj zS=LAH^H}~!v4d@%)dv-GU&ZRVe_}aH@dU-(_pmnnZn5QZ#SMy=kY#+}{)FXKip{r# z#fJL;*5(Pt?TU9P-lzC2#Yf45(D5NB6(?aGvU=WsZ8@YkQ*o~1Ld7MDx&5_%>J+yq z=62TFtW>;C@dm}46m$Q^j-@*l?^S$2@nOZ>?%KQw*gjYus5nh=hGOm?So=K1Qx(rv zT&=iC@lwSr$g(Y1tGG?^M#Wpn9Hb%7D&DPlzv4rRKT_;qduX>cLB&H9rz_4P%l2r3 z;$p=!6_+b+P`pI(GR3PDuUGu2;wKchE8eAepW?R^A60x(aT4|g?6#Hns#^{z&QzRB zmhEq$;u6Jk71xo!>@BYr#jT3@jdE+VPVolCn-p(Tyi@UBa>y&|fa1f7k1I|{irEiT zoTfNKagO3V#Zwi}R$Q&PN%2y}D-^F)+@^S=;;o9GRlHmAe#M6rf25eNld^3UR6Im+ zy5cOw6BHLKo~gK8af9L|ikB%~rFcC#;w{HV6+fZ4UGXl(`xL*W_^9HOij%OPYs*Si z98#RAI9G9@;u6Jk71t?lQQWF{rQ&spHz?kuc$?y#iuWo$p!l%j7IR#;ylGu70)IQ_w1_`Hz{699_iVvP`p-go8pa%w<>;C@ovTY6(3Ukkz!s1 zvvmk69-=s1ahBotB>;f8vAmaU>;jCruR>!s0Sthx$MsW+R4krytmSzP0EO^7{8ZF0(+ z0Jh8+ee42_DOdrNtLGl-cL_yHDwQpufAi+mrp>C$V+S%Nn|?yFZxU zeHx3mPuO>#qMyC*KIN2$@Vig$_Wb>rQ$DfXya2BksOaAN$KZVg*<-SuG0im%6(&pf z>6qZdh7mY`L!d1a(v3z5H~G0I>b%rK0fF=*x})`YGJ2$Z;)=I z$7f~jW`z9RSL1GjOx(0?!wd%tZ_Ph-jL~zVhnUZ-lKD)WyavRMA7y2=iyN!T%F@T> zjvL=KpGrGEw+HQo**)6kT-bwc?gg;LdqBoiG|wwr)X?N5sw!jL)Lg%Sp9_j<_}UgP zWrjxN8jWKVxG5)CID{j2RXY{+8W@k)~ACvbM30fDs8M1tkz+!8X9hNVSc!~n2 zIC*-*NRGrd!s#C)+#TwT-Q~Ts`&uvUZtJBTFBA5revkFiZdWhu-tDE`={%1N+b?S8 zk-fB=+)KNPUfSK(OS{#*wEKB4?Oy7o-N9bk@g7H*eqlSCbN0Qk<9qLVtur=2;CGC=GQ8HpcApqmY`MIiRAVf>KU?mCxNR zcq+mAI}5<&Y?m*uQQ=fVmso#i0LXbVW#FZ;`tfuGr?DPi0cd|4;SZ;$x`cL=aR722 z6Oat$kLv=b(Vw~IgxJ<^EBvudtXO|n$N9^Hza=oDZ4QFA-T8QoXI|~!!wpnOn>(TF^*X8p17N2pqLVuL40CFA^ko_o^ z*Ed=2g$SI+a?Ld{#J1dv&_KFh(KW-T$e_#Rb)6qUZ-xFSynaT`V*;|fzt3CU2Yk;KCzz@MQpj*u+!y+3ULp%EMv@iSGkwR`AfjL z?$@m|v176*&fnq5SVkz9^N}xhoR2E;XXoQh_&XDND|SA<8&@vRv0r745Zn2I&uW>NtNZ;IF6gsx;2uROPQk z`D=>vw-)~7k^ro{`Cxo~oWE-LD~6u!T#8`lcZK+~?ffMC$z^3&#oGC&apm%y@ezz0 zR&2ZcD6ZU%D7O_8SuXpvE%&Loa-YV+z1%uOY?trbapeY+@f=qVOG?=NmD;^N1VU%uf~=y_b2RpoD=772>h`hS+VVM7VOA*GGU4G z$9*m9Z(N+ebod)Cc^FxLrDA87+Z5Q1Qg*iemc;pMft~$Yh4!~7u70afKVDC4fl)bv zt=}r~XBR>CS>5N?u6mEe*MnQ2d)zpG)V*Guc~P@G-O zXVk9)c6$H01$MS=S)SzpjCx~tW)F6@PV{GaR1bExEM4w+*f9@=C?l+2PxE_4oWI*) zXWNn)Eq^u6ZW-*-JlE#m*5MW@H%q3`&h{~?SSN;MutO7e$rjk_GoWJT?&yM}MS^1;AZ6l!b zELNfrI_hHZ)d(z?{Sm7|*RlXQZ{b=P@5!}d%f;~2&8`jw@;(GB*6#dh?zoVW>~Z5S zyfACr*bAbeP?phq|Jhkt<8pFBq3jF!PbokBwnxGV!V+zf{ z^D^EIT=>fMwf@0t5~hFJ**vIU-5ImT-X0lVepUO;wUsma%^BMqNze5M2hSN4ecrus ztQ$0pURgOjE9+m;Nxo<#Ju5dqI?0Vh(hDZ}Ba`q2=h1!mdGX4~h}mN^2A^Aa z*;U0O=8QeJFfyoLUZg!TqhBzE(^*qi$u^gb|G)iKY*(qQNrq_}QzIA5X;}#D32e29 z1Z+giG^VdXps0n}<%c)wFfU_DPd46^p8ik$u87XhMakY5lmGkQHPL${EKhI2n8wCl zi63t@u)UARkjbbYHnpau*phrtJyuK83Oo*BIvr`YP>M`C-aj$ujG0nLWfZk6A1ilg0l`#pQ|{$aXOA z#r1PE4?eM6Re@9N_S!jB)ip+S>UGDiYZ5A>x!|C3nTr$Nm4+yU!vqAe4ZVrQ6?jhZ8OLFvv$*9!!_)S>^T0%mup7>OfvnQaj9?~6A&Ixv#)Sl zzkgE%#fP&T?5N z%1(ryw&|>o-ll(obS{Dw+kOv0VVTpSNazvEPP-q|bp3dak?p{C;fP}E_e-$N12pdr zTtX1B(|(Gy_Q!juX-9tpWSUuz!LmAnymyQYgcFWEw%mc>_-#7x3+EVO#g-etO>alJ zTdfgdYj^(GY;U6-^5l!Q>0@Ew?F4-BHhupB6ohiUKAnMQv~jdla?FRo*hNS{=u_%* z@pxwIRmpi*g$jH=r!cu>Ccqy|X)Sb13PaOB?7TYl;>j1JO#h%W=({>K8a~=NGIhuf zxOS$$-x-WvoqA6AJ*Wm``uI#xurfGv*P7*MnPBD0i3M%_3MM+-raJ?0=4}9;@*RM? z><4UQx(`AkLc(X(AtH770Cku?`GT{;@1vk-Hi}IdpPGkaLxt@@-wtj|!iOFsr6!gSTEMabjzsMCS#NHCWfLuUj)w~g2#qh zBW_kCl>K4n_>`d|$0lVT1Dv@d;ADRQ7?gdK|B3JrOhHMgm+J&em$Ss??0E>|EX`|_S^~6`nhj0H9F|N$v7C~JRYAA z{&VNF;6D%6^}o2^=mG7C&iaQ|u7}OvXoIJtv;WXp(DuR6^F!`ms7YG5vtr-$L;1(E zQ=Sfa&EcdxeY9`($^!ROV}J<*`yIV)XJ=_Fz<5_o~ zC`jv9y8V;u)8|Zx%3`e)f(f6Qd4pSNmQT{hf(mdT{eql5eI+4*3~ z(^=AD7^AaV&}=K;%>J}9*B|w--!e8KIJPL&2@Z?qJHd(3d^h-bG~ZX?t4XVh=KDXM zIs9VZxrK>|PNly#*r&X_`kIB!r#bV^95M8&+DXTjV`v(`_RSqwT>lV%!xDnS*k=bt z3xcTj(6NdC?leoraY9+uY0H8SO&)aB_?!{J$3{FnEx3JrG#D%$F>zw_nSTWA_=@2jxVc`Dd_sIR?iKZiDacQ_#=- zAKZ7(p>G^tsFy#g!}aEc@QXeiXZ6jVRp91-(pmaY|7cr6q^;FGZk#lv zM>5lcsX>2Ib|`1fX#dWzEJC|2;C3NlNJq}A^yjRaIu;=ZX_K^nDNnbb*nB+t!W*yr z;U7<9t^43-=a2G_awBQ|UiHt(4nCfDpk*YwUs};Nr}X6^=MEngE@*2C`Y#_nr^0>D z)Z?6ix#7sQeIn;1AA31Ha;-mODRLlEEXQl^++Jwr%@}l;RzA z&WO@$M>J1bUW*Hq<5O-PId(wi!{bw~&HUr|)xM%qXL-3Z;g91}>Z5J1j!(IM!m#lv zz8zn6mSZDdoII;~a4_Y>{iBkLu69oRJP`*7C+=Q8(>XRjC2@bK*$RBsAQy`N>5S5pO9fjSld` z1_MiIY$!4y!HFbiMFD+evvPmu_|*v~UfnU?*;1RD{X?YsM+PL0NOAW!pZK(h`(N4L zhqBMH`GadVw8RG|6CJ>wRwiGS;f=YcIB_>5i58QzbIx288l6jHQ$tNE= zHh&=2?kz>p$N+y7b0srl<_g=$h1@hgHgeqhp~cy`(<`5Ci;Ns!5O$81g;1Bs0QbDe zxt+OTEbm7mzU6mzX8b&uxqdr_WegUN`HIeU5=S|~V^P10(*olkN(dH&c7-zT-<5(l zDMWm3v@JC9@jj8ZBxn!zOK@kiZ;kxLX_-DKP*dt=Qup`ByU~6Lk$!zf4oWZ+Gwxn_ zI~;r*^#^^U?#6trUyY4@#D~%6RTP!>cG`x}q&p@*o)Gj!<`2Y-ZmjG!{YPolW_mKG zCl~p!@yq?)tg-(}+}D}(0S4zk?0nwnRyCwvEiTPOBPiu`PM}mpyMYSpKzHt=$R|j8nj|JVx6?aAo=UwdHl{uxt z8^A)LmdF)%7grp6`J+hT*Y*Vaz1z?_I(bhp80-^zHB=P9TS`YK7E~n8$*-*F zi1uGuTroSpZu-Z=l1%oMk;3|8FP|KG)#bJCoZ~Bct@AGz>|B0^6Y1wh`#D^skx;as z4?91hVE}*YSQlOQ*Mky&yrwV5^3_+|wYspb^tqEmYfJXGKXS%tH;#J-`#uA(0~GX^ z3|oUTuy=I(6?ffUShxINod;e`e)rYC?rILYr7w51j!bS2I>E%yjiFC=ZQjxu9Q7dn zaubiBA$Pv9?+>~ex!Y#H1hh>bN6CRa)u^WVX@)?Ok zBbSe@E%>l&ob$4oe`I+j`Bh)|Kb?KEUkFF`paZOQPq2kv^z9xUa{o;X4thS~a=^?A zCF~6EOE!-1!LEx!HI3Dw8)}*t@sn@-WR=sUomW-gREN9HjH0QczWK)bMKvK$8CtX$ zx4MU_7A$UT3E^{mI96||sgC7s5;J4)`95N~>l<&VXsE9aN#;|$d5ZkYr+r@OvB@#V zW)3D+G{x7nWZLCZ3VWUjZxV0Oi_bKuMT9GiK(8@JT^_7H&}{=xa4qEg`x8 z((ycv2$ghS5{p9f7o(DuHKF`TGe%FGI4xAWpqZ|nNi#}vqvOW)TokJCnI+lfP;vcy zhs`;^ev$dY+C?Gcs$Uekx+Fh3x@5-XpFMF>Bc6l6&5(;~oYEOrOhOgV%JZ8VYS1JX zh2Zz%;aJQvBVg5?yCIJ~2P2F`C`Gs)fye1>2%8ahBm4v5B*K|ksrXKx*$8|G<1Y~S z{xHfA4EX5?`3N-#`rN-}+Hzcr*HNGHblaYaGhX!_s~8mY9Y5l$ICFc&;DZ&Z9PrNB zag`h1-5H$NyvGejBa`orO#517^2*4x`sn1lqSNXklkbd7n-^RinS4)VTI0b1?mJ_A ziBsI|1N^O-$=e5Tq<3~Dx3_1HNb@C5bi+?|mcG=H;fw6?M}6fHUj_CTrtkk=_&1#y zzK^56#A$B$*PZ!Wkvj9>)a6q!lkZIOC0^iO>_%QrxanzcUn}~{*PFw^@wfYSjBzxHUagiJT5&6u6z8&M;{2z5@KinBCn6nu^wsP2*y?K7{NT0;T z&O5`0hVPTohq~c)o%ugx>6N}6{oNgd-O>SlgZ|dx$)y95R=;#SbX91yza;aHRnM$x z-#)Oty=8n_W*D1AQ}-{s;T5LhzM`RS{#~8f-$IEf?|zmyKN#%4e2(+8D+m8-@(z^q zbuUv&bHdX*kMzy( z1=G;9%ingwS9Au)WcWhw4IKPHZvKqU?5U{q5ALad5OZ6@daS$WNZ;jWJMWAd8lEVA zpLN3do%vJ5?{l3y{u}Rraf7F~4oi+E;F1HjSjS%Ic=7bnr)NEP$I;<;gmw-5aoU9N z*v=!To95l|yc5p0#s2sK-;QUT{Ag$P7?k{zg{I`mEcwxeM^3MMaLLn&+Z^Y-^uceQ zR`iq;jz}FIcEX{~{83Ve4V^n4aDop-Cf^mAR(B+LZScOeJCd9WzcFVs-JzLt=y3Mt zb@wcJy6(YfI4SgA2wUOO=iH;C+PNKm#2J6V%eChW3!g6j?{dOPo%t!^e`V*6<<61d z#XKByt_=o<75JRTeD0Krf|ol6e-s?QVQBb2SQXe?mpb83I`aE?8H;Z1T)qS^r1ayU z2YaDeIV`n(P4f4Dd3N}HFT?UCCw!zM{}ZIJloFdeiy9n^A6K>yZaFP@W$^T@U#|J_ zhP3coo^@i46F%6H&%9iwwVgZ4aZx^Uv3p;{o7dkgbU*39yaw0I-pt0^x^R5TsO-HR zx&DvG`j%hiWbXl<`KE72sgwVDNA@2&uJz#v={;saO&o9CFRsYQZ+$X3@5#{M)rrwC z_WN2x=MCIA=x`*wo%M)d{ddCcti(ZIQJ$0kVn_B<9l>bg1ZQwGG5^;ck%#@!)Ey%S zogLl+qru1eW&f%p7|HcxMPHudeL9S4Wa7~JTNDELzT_d2p~?})Uy?t`YegNb1WWsE2|v};5# zWn)eFM&stJ@D0XIO8#9P**CyVb4Ad-mpPU^jU(31&dB8NMy54vpS)^2n_&lbo*!^N}-+1>wzVXKK&c2&@ zTIa+^ym%bP>|3V&_E@lQ zFroGQ+OvI$uXaXW{1kq<)%k1Zfx_g=c145ko)}+ydwu3H(($AulsQ}#(6h0=y!ieqsw1lHyP6QxX}t{`S)TEA!Gr zrO%xx;ga!X4Z{iS790-o7~{^s*sSzBk~W`uwjzukw#SY7Rt8hNW%+SB_SOSqgJ%R2 zvL>wwrQ>`bTo}PV`s}eUgtrgs_eyf#?0>j>o*T0C!;dq4MVU^tk2|j_G5cSgxq~ix z^dpTLs{iT12NzI+?AC< z|A>_29YH6$t0S0-8NAqsK^^Z@-qq0_y#wddc+k}5Zi)D!ZOlFua~2vq5Sz-Ztn#F6 zo^sije8@FN5j_8!;DpS4;t!)ZEG=gyF3!dpOySx_v3qSc&8sDpEH5%wPl(peP7ld+bGjUyDd~7W zLD9EKJVava$L6QnUSp>ZH^ZyrMPT--D~){v(HQM{29H-0 zSx??cZ0nf^ZbqQZV+a)bB!>`azXyRrJ=yl3SEz(gPi9%Pe;Y+mm`ctYCzCGGqFmgkbvy@7}cYI18MJz`S!2D9l5qJ@wqvq)<<` zKI8is`y}meLZHx&Z1s8_+Ouy{s3+U@ISmbB+k|i4>yK%)A50~L_GDX6 zeg%V*s83V+FqIJM$?U`QW1lvpJ_CANPo7PoP*1kYf^R*hP)}yLK7@&2PNKdLVB35S zl@RL5ww~94nUDH%u&qz6($|5xJZQHTOrbrQ?L+-fl|8O~n?6SUR%K7N>*h`{C(+Lf zfCysRzpM0z!Iy~sTuk(XX+Ijw11j3*;?LIk5-K3HA&)~$RSW*umm&!FQ30V1nf0Om zr(in}M;SVNzBOe2pJ{f`jav1lup!g`Xe z&Ff$+8lyjem}462e*%F*d$R4TJgY#Vp3J^Y`vFQ%rhn?kDLt8EDfN?-9!Vp%9hk73 z0Cv$PjJb_r-Vj0%A%gH(?Sn~1tRLFb4`b$`pIijHe2c&o&X*ONw+#yBWgJ3a-gX2E z?b{JL-Ctrz}_5nJCP)}w|{UD_$ z+hv!jY;u$h*>1}wf>|7W6@q7q&voEL;RnDG;dU^E_T&o@bJ_`|C);`98!RcbCzm0n z{f%H-?h>$_msVv@=CYt6y!*D~dDJ+|#R2TWm|$a4`` zw_hRHyj#HB7pFb|rPT)k!$r@16vrm!rs-8bOZJ-FSce?9?DGumtb zq=v;%0blW80bQpPd&>GSX9C z>X?@?B2#u2V%CL$`>`S6X2cZQl5O9P-!5}H^DalAFip1O(%oP?zw!I|b{%{WHWcP1 zTm3Jfu484-%x}iXSQfwO4?6wjSOVlX%OR%nn{idAIo`#@Z~C=Pb6+JU{%%jc(f@g| zi6Fl-Ixc;FT$2|o?;~%;MDNPuS05;_uc!SReM)nE1Or*~jS|vt#nb z&y#TdjtOoojwL{TGd9IkezV=s>6BQ)*mEB`CjPGTqn^%h#y~xtV@*u_-JaBD`4eLk zLH@4ubDr97&XdGU{CE<9ONeV1*DOB&!lMkPIr^sH{31tcD;#;bmEdUgI6?~6hbs_U z;dFa;fjXvJ2qH|cwh6>cZ-`6(EH3@qxb*LlX8m|XlY;$?cM)?`|J0<1JO4p!h5mUY zLHnB#QgG~Wj&#XNlOE+mSd1M?ye8NmW&m08+r$Qn3E=+kaMQ zzZ&UG#ADFaQ*hV*PvWNUh)chTH0O<5#uV%){u?pt&ygVo>-QO0g*eh)WYXizH++Cb zSf05UqS7U>Z$p}ULn)|bwOR#f-;6W|(!ZJVzT(`4G|NjzNWnR_hvMvij5OzWznOli z^HkjQ=Oj%ZDL9A2?--I9*uOrM{PuY(9{n;4*9=Z~@OHPd<|S2?4z5C!@iwQjdfuYa zSkX|{Tr0ym4iuD zO*c7BO{FzeH{n%>rAtb#Z_#%2AM@H(e^V^{!+kC8w9<8kdq?J~@rFfe65iUjxT&nE z?xwQ&3#x0>1lASmX57u?EUKS}x-BVVB3s#bnW#URG~90f)8`I zR+)WAo0?i#(}K=WhTFu->`h5xjmkDGK&ZI^?+W!8EvB-1g(0U|GPJ!BFM!icYHppv zyFjZJ^UZK7YyG0KI=rdWyUDJqYJQWN=DDq?YT<2p>>1srswIHNH{IFm;F!4ul~@2Z z3sKps#wF9{H9KXPr>g5~s>^Uln}hX%&j?bu6((~Xnk3A1@N(hn5SIvZY?v*~^}Aen z3F5CQ<~UBD)N?E$(?@~Q7YkP-=AOK@|Eh2!;yU5Qh?|7za{`$wHpJ8!%=();gIWI> z2()3HjZg3m;BwKk{h{4O zgp=KI2F;(%Yx)v1K}x8P*|%s<{~-jID+gp10`(!`faueac4gOlo!C%E4v2n>=-F0Vh1q5q z2sZCF(NjmZc{6Fl4gz@zfpwsc91y+f57@otnGcHf833osZa3NbWYtr#pm}tEi!dT@ z-GM#<{7cb4jre6@+W%SjHN=O76QDm|I1e#gbk!k8^wg1U9oScF+ZKuqb!6MNrJ{cf z@odHH53E1+)rw6Y5WVTc!e*HYuT}Q<3Uh3DUicNnzZc$vc$e@8h)sW%<$gf))RAqS zQ^9t={tae5sUusPAvgIe9(@UEGRIeTaq=w0rNVO&&k=4w z%(Ts0FU-7VTteQPz&D7VeohxoW2~4*uk=HImkGBZ=DJM%B*e^5X16!X167DVfzq3{lDtqmE;}8B z^-INyavx&TCR}MCcOp-o_Zg)@QfqsUzF^u&=vP?g23CLmk=H=N-|%hnRiQ zu2Y|go;tE^6JXc2?@Vwi8-XzcI1{m17BbEc6FqfgJN}!tngRu6CPHdI?<(Fegm3ZT z2@v5H@Shd4uC%9~VJN#Y^ZR84>bV^F{ckeg`^qc6 zWG?rw2-AL+FqiN5g?UBw7s9_q{0HF!h$mng{qX8)kub0PnsEvGtKlbvVAsKUVA@kh zw(B7KH1%B1Og{#PF(3ae`d1Kd7tVnGIbrteox)s4elI*2%xUz=^8 z*Mzx!c~iI$`a{C(Q|}7%%J_%E<*+#+TnFwDX1{Y0ST5U>??$#vzvRmhPgZ*7r=H7p zrSMwB4Aiq<+^4ur_(zBz7G~aG3bVgFDa<jn87VXiMZiYE%&yD3~51IM5qsr|hx_<6#Jy!}S#H-dj9dS3D0 zFU)Vw!qxGtHO}J^<#pKt1Q>Jz=hw zT%W1mikRYZM+U*j}i_crr7o$1WrvhDsTIBg~uV$(;qn?dbXV_d>)v2 zsUuq(vo8mIE_8JWZVLV&)d-f$70*>Xn>-GG5N;o>eTm|!ii;H&D$Y|pK{4xOedZ|6 zQq1~9z5e0)=w^I^tk_;1E~Y{q9P>t`x2 zpWR~}*dD*Jeo)qH!mQgrl)V{~VIP8?=eC)bWhHTJ0kf=u!gs(A?>@2fXtw*X;XIBK zJ(myfO0j;jg>UWSIC;YS2I~f4*5{YP^z)c-2KaZvZ1e5P-s~Glxvz;n6ZUTiv;H3o zH=+I1^pe$ez|ZV^!EsJzP1Q+UY-_aeRc^KgI^YAd+rxD zcTk|;*s=n`%sW_kD)>vn%==~G6qL)mYM7UjCCobH3e(RdVXpqg!t}%UIx{c(Ex)l! z=G`^r!t`^!F#X&hJQIAAF#RkO=De&Co(=sbVct>m8)2xOr-lEF_$9>$g<0-Dg<0+~ z;kjVmk;8hj+)sqr4!k4BwnJZ}$>p%&-8t6&EMeA@cjQoC4IAEtLuR?z!Yubf;W{wC z&uaZ#AyOL z>~DQ!9OKx`{dL+?9}>P8G4I@^p5yen!j-V$^+)PC?$VAt5pkX{{WPE~7j>j?Kbtnx zk$Kl1$6j;n2K`*#$Uq+kxAZz6pNa8Tf;INA%Q@ z1EQy2`q_q<`|f0JA08EE9Ud3v_F;=K`wp);(w_71rZBe^?+CMQ?+J6e@qyB}pdPkv z9ipd>Z0pt!e(9fgPw}~OGPfZ^g;}>@!rY#WQ2HhGk2HnXP??uHvTgJ0ME?!MOEJym z0V0IgSZPlkIUxGQ%6^S7?~44Pa3SIcg}KlF6Jc(z%y9vHvd-qX0L<+bk6l?7w}H$< z=G~J2Bg}2rOTz5`e^cCw`q?%-EPCq5whifvK6$65E8{=6X$iut55EOM8*bB5gjt_l zVcv~dAk6LCBw^O4RG8bktCW73s#~q-sUzFE-7NZ(h`%Y!?cNGu)@_Y2w|n;rvu-Qs zA8E?3MNb_$z%+QT=>LlNFTySG$u#GecZa?z%)33`7UuTzkTC1;p)j|f9}BY%gOG=Q zc=zUDVcs43Wnpeh!@~5FDa>u@`NH%wS(tZ_UMbA&YN;^uUMtM)YPm4;UN6i#EEfJA z;;##Hd)q2ZKX(apd;1+>`dNwgvg^ykqNk2**O$jde*p25!rVSTB~1T2gt@JLLFre~ z{|x*=_&#H{8+BycAMkLa(erNAlfq$ehcLI#eGr(J+x8@3mOD_G+xbCC&-}FKwqUd{ z?~=Vhn0YT1=C-{+=~)k(w?>%T@H%DFB+TvkBBfu8d9(A&eFFNSj%??bb)tS1Vg@qr zw*7(P2NZ7+eire6D`uK`dFSo#6*Eme_ZeOn=C=Ls!kqW_75kB!F~4g-8}fSPzfknlk*)u)iGD3&uEWgBeO~T2 zleu5;b<5E6*n@iRBP<2V}Iyh zgwE_UfHR?=fIxfNlnU=f+$OvUvDu!&<|6Q4L{Ix1@n3@2oYQ~}xk&V^3s1q&e+}$Q zh36oiD?AhN^@>{*V>Rkp$9c|zeyAhcb$prV>E~|6_bTSTogFKl5xb<^|6357 z^C95Z!TUu||8EQPe9j@I4}$I3o+9l-9odfUY-{@GdDJo1262us_rJy~t`z2Z$a%u7 zgE@|dAMQilr1S$>2c#)?h@LvKIfe&+TlC*Wyi%Ax;jSyM*^h#PI@yVGC%K$bc|jk-hjiiiI3#-J9U+{BI9K=*#JsFx>yR(ZK5P2nYyf030&S=x2Sm?ZE}NHm z$ZHW_CHx!2*9fx?<-)fjt`}}b+#tLh@eRV9msVl+aqc(JKl%H@4XttqATJB-y9JJX*2y#Ud@6d2v09 zbfwQyJVCLkv)Ip6`f|lwM%KTno7gW?`c-6%*%WRYEI+FF3B~P-xty&1KE-b-KC1Yn zVvg-LZ>r)D*$+bq$0Ex-UuU^caf#x&it7}&C~j5EvBmmari`N>{iU<0jocx z_#?#*)^BUWeR|70X0V*DI7>0l?^&B-#WNL`D{fG{MDa4ks}!$S{HWq56t^qhrFfs> zw-g^$d{S`|w$FB6c;B4mkm5|mxrz%FmnfdAxK444;#S2g6|YmgLGdQV=37_&y!C6R z((hG#K=EP4#}y}FoU`*gP;r{#48=K$^At~2JX>+K;wHsQ6|YddR&kqRzJ1@;bF1QK z74KHOpDg=JhZKLLn2#P=o1o$$iqjQmDW0IXSn*87<%$~=FHyWq@hZjqUYf1jql%wU z+^%?+;(dzWA`kHT$x-q^kNIs#%SjlUE%UxP%OS;?igU@b&snIrMDbk3b&6ZavX9!T zc%|ZXiZ>|Uq+K;wHsQ6|YddR&kr+ zjf%G_epc~r#rqW>Qv4BFj*EGdvE`uRA&S!#XDObbxLEN_#pQ|{6faS{Oz|qk>lHt$ z_zA`BigzjAr}!DaupXUE>S#JaUEICIkYHlRlHL1 zI>j3lZ&JKX@lM5i6(3N1Sn+Yi3D}O=x(!sErZ_`!j^aGUQx(rvT&=iC@lwSr6t5+p z>20Ii6mL|#mCTbgl-_**t*OF37}xayI6j>x56gAaU0-w4e7uaktYtx2WqnI+eN97k z?5lB~^SEc16aB=bddjnF`l&wR9=YtY)Sjv;)W_>$6XKq{>>;au1ha?9>e;{8Y{vY@ zKWy29hi(sCe&%#OKiR{?*iwi+NZEtg=R8r_gLUj7${r@hJwMrlMYjhjdzjwsVagt+ zt0u+clw&^c^Ma~hn(qmkj||4z#2M3F+hgC1nVj0Qx*kRz<9(@cOl-;ON07%XYH7~q zM+{@WdN$M+rHr;x2PX?;-b!B6-b4riy$xHV>{n-|#S9?v{ zb7`?&zTRFMR`R0;dHr?`1Q!z@%jW#E%B1V=h|)Qp?)_@9!7S(+ktEe;Jq&UMHhJUSqcY4#w557|xei zXJW@BpG(p8<3sMdpr^ky1naL4uQMQR*Q0hMzJ#7O?DTYF0H@DIDd!6 zJ5Cm+)88<$<8u42IDfoG^(9tZ#QM80&fkz+?|uUM8;)S>_uDvsyw{D_$*ov_zl!s> z?ZVh{8wq3U@3lC8%P^tRIuko4Uy1X#;v(^Q%jasCd$Ur+POo0jcZUBE3~8J z0mykwKyq*s53eE7AGf8PMt}1F+TVu0D1!Ngm6(%_iO?T7%(%SL<*V=h^V242#OX;CO3ix z5|W^3u|;ap9%+lW*0!`owAHq@UJi$PdazB<;-#oSZ50bgptM!%B_dk%Nap`MYrkt| zWio-B^ZUN@ec$i*y|A*L_3n4Q>s{Abd+oi~g1$!h%*T0fyheS80jN*+-|M084xK6R zd5vx$pHsn4)GyX;p40*GsgJ~W1f^gElw&^Trs#VN>l-2PHEDfwQuIBtAUUq_{V%PrDMjCF(04>D6FCO2P0_a- z`qm;Jw2%9$Xnh+}^litQg0_izH2#^$=_+W4oY}54f4j(WEFW*6LutUVV;hWz?S66|a8uz`A}` zOFz4^pRYPbKCb97jJAUUE5Ys z(T0;|uHY#>pR9b*SJl~eWAN*Fcf~C4oaOuM+w)cjkCqR-tGxfZ@~oEf0dsR^eZK;#8QF8rFR6D;XI#DQg4MCyU*$2#%Cao;=FauYsfdb#SC~@}~Y- zkfHn>3WL(glc)9bRY%I}pT1McQ;zbVha;Uzp2G^|E8+Nb)P<{qBbjkMPRid?@0p1Q zJ_hyN6Vn(dA?H^nBqQ|P<5G`So{V3aZpxb@9rdy3lk|W6o}u_LGN|XCvgREJ?HQ?l zUvxvu#~!0Ba27NhQa<+8Wrb+sI6n`L@@zQycyP2DKIPdk^05QceG+EH=cD}oUBZi1 zc&K$4KI7AI55?o~8K3ViG0b-(*#LMiqxM)#E+fTiYnLpmTXH?lmThWT!gWV%i)ike z*HfT%8IK25+wbX}5KpELE0-&m#8#}p?sz8?ThVmGNw2rIE<3qd%VR56)ngmJRV~H2r|nJ8RO*2Y^$@4igQ-bkzb|5KPgM9ERAw32 zw6k3JeUeWeVwtL~?bZP9{i$@l# z)!BiQmhtRBFH5W2SXs#cwn%M8Gw(C?^|{1F(8wWQx}My#B$JUYufF%_i`-B8sPE-I z%6-yDxwF~7A=_I%c#XtwoQVA@r0>xr08h*Ddnb;^r;?j4`t&`zzGu}MsgG`@$Z7jZ zz$?;1@O3#iLXNmpuJIjPj^X@X2unEX8pn5jYfimdUoEhnlmjO8@f!zIAK%U87*Bni zt@0Z6?M~6R8$8Nsq8#b>Df;-1ZXx*8HwaGa^Witgv~L6gvvFOM)^{RBAK&NI_HnkX z^>I%sQ(qMVdeTpwT3-lq#HD0{_+GEp#|gjI$Gxjeef;L5PQ~#4Xnpfj^zr@PDu^(@ zocd^e>e~v0i{VJzn_RaEhM5-Ko!~=7f-XjwZ9x-dNDqLoF~fY`qIEN@ukqVUGrxR4 zSm&3sac$pYDf;*wJ)fy*((vag`uLtO<(OZNDOw-pA)285=qR0F@)?3Im%+fP>o&VE zCkW`oa9zXHbsN5O`|m~qS}ys!+|V|u=^W=&>o$?%^CQJ-o#)i+HmZRlA9~&9GTfa6 zG6TbR4#axk%xH#PdRtj(MeU}C*ZuC6O$#fo2wqc(Rh-h&LaU(Ey7>OJvz+Kf*2sE% z-hc7fmvTDsqf#AnT5u!Lw4$}nS+?T(SmUx<2amF2%hjyhs=>bFOPgA5oH3@>@pjE7 zs$CYtj@(4p9=mN-D^W}9lIoa>iHF@YidTv@Kg+*R)E)ZOdvQX{DrEQ$3Ap z9PACh!okZJb!~OM%2cxvw&yo#LG))k0du_yvOV$eOK~@5xtlY##B%J{;_cYkFPKx( z5!@BOvZjB?y)xe}dm$cvCLYMQ_wZ`w)!0wREiT&`ANG~5K<$h{69?M6cwyMle(s=t zExDQ1x&110GsfTI4$3HdDn5RtJIEj28Xq5X2l>X&a|hYu%iKZM_^_KhV0_Tc&7wv9 z$J@~VA4-227P}&4kHv?rI}X*qBJYH+>=y|C)7@2Z(9N50&cklm{qa!7uxqkQ1`hv= zZ}!>Nw#e+@58@%;v(*>4r}uAx{*~_Ona|H-s{IyrFv*OvAHwHKP3f;M+Yk@m5=VjAcPV>0 zh=zVqGBA{1JuugCSGkuKuGw4c4lbXGni)T^^7Kr1pu;su`!*$y@p4xU$f&aW;cf-_#;Q z6S{nCdEzIsGybi(6*$UAAqmpIi3vsu$nR+1x95|`2YhhC_xz!^I?gXUkP*lqcHwD} zbBc%kVZ@=gSJoM*pFt6%gjjIEwGY~9e3Eg^q1^6#I` z-w~0r|Egt%RSyZ-BO~YAC1sH)P6Z|0OAr}qjf`GmgIRyZ2nGq=p>~Pwgv#8RcE~>4 z9gn|}p+0rNXIy}e$WVVI>T`$syR-K%jts?`JuYMz7ocd=I(JbZG(FHSvID8%ta7)# ze~6A#~~+Lt;}KDv4LjKIV}_IIghr{5~OD<0m+-uP`Y0{K}V zJa_1|J#Tg#e>}gVH2F9J>0#}xqqB1Kh0g~Egaa8b`rIM6U3_m=^bdA4V{mD-Ffuy& z(1%%(M>n9YVgt~~qmKX-`O#=Ux5zEG4$jJBiI>~aa$mqds;y#-<2{rp`+Iz`ucR>e z_xPqOB2ebfiAK+l_ydt>Nx&Z%z8>?Ck}1PR$1{(|t>T*CwROd%h3hbxP5kuEwnk2l z`bu`!<}Dq4!1bLU7&5LPknIL0qi-X1r?@REj0XngL)`L$NckXl*Xhp%)lu-sQ5L5) zpiqWw2l7gQ=oXP>ka`{wJ{IrzDDI2-Bh}GJz}he~d^8S-zwTc9{7Bgc@yO;;k?7!n z-`(uDJ6W1#@5Tc|0uk@gfr~hI1>cGX?v{r!;e;6hf28uZh#QPP`rFdUgCo^JDR-4F z3fe`9FRjjMFLLZpsn;zEMjkB93L|%JV=$q{QV%M{Zp0lBem=M_uhI=-Kf&nc((26z zN-uJjekUusc`ZQX>5OP~u+r~``D^R)D*e7Hj8K*REBzUj(ZQAeet{OtS6b12XM1}F z%5YP8@Xh#+rw6yUw~fol-SPAYfZ6yR%6990f7)|64&x#@mVJo!ZOGp-7tdq(Y{x5T zOkm?L$K&y@bj7W;z`u>hX{O5GzPuNGrLQ??hMc%{j#nH5Yud2-?C96hkfU}_vgRpM_C2@6DHap)3jlm`l03}fn5Rr z?iG3N0lQ`MR{|sM+I&{=15WYG;HBl28U4^iFJ2Ie`tolm7`JwzGxevw&DS_jWi5Tc zern)j3kLW9Yhdd50VC&EM)NO?MrI8eIr)aWpJpR9o`#`pur1W{;ppZA7vF1NHaWW2 zUYC)-{mGVJz8lEca{rJg9$o9)(0Dt@IzBzK%ckcPab755GwdPe*=+vhZ>Kr;Lz#vD ziFUZyHz2%Yv*q4jKcRfutZ0Vy&ej(uPnaCYcV}9`PBp}rqEm2+Qd0I_9DQPW0KfI` z(dyZl6O7zdU;a$+ukkgX@z-Ez@Q4!4Df??2JpqF1r!y-&F(7@R1=DN%^mA6t>9n3E z8_y$f-&JE#30jl z8wbaCKzgJ6j>iti2K!<|-u3N>R#FE1;jr*q@#>5W*FPL{ z!wlc}*xIpq)fs-L-f=VfM>Ddf^G94*Ot^{{WJ zYc1|y_F_EzBFdJxjaJ#Nc;y5A0yB%&QN!2o^d_~`aQmJ6qh-H~hj+xAuX5bYw!Kr; z86HfPl(jrtaqxz`n_9<@tEvxvecg3ZP5|Ihg7W(#>^u8P<(N~-Q3T9gsGt! z&9m*F5pIa6z=m&49Q4np?1?!jnav0C4(`ee_;&Ad0u$YNes^95;9@(v*^X@XADrau znCG)MDLp=4aLA5e{@!5T;o#uoALMsb;Qn`cYwarB7&SRKXse~os;$F2`M7hco~W)A zIdiX=wZP%&T5Sz8#;o$@mk1KqwKd>qE1o%~Zgx?S2C-4okB(Du?7A`I2f2ZvkwAfWpW~JX)MO@SM&OR3t8M!L z%OW&mp?!xteujHSj=STyyErG5yDd6eHI`SaM?!UrQr$49>}9r-<`xI(zs#6fk59~b z?*7;AeDjv$EAu;wb2_~e)8*I}Yjn8w&LRt|LaN3XB*mIeD3V@C>%dj?)}~b}YF9N= z)M}~Y$z@c}h|5~hd)u746-}#_Hkd`N#;Gyju&2%g#N-b(Q$1w4zjBBgqW+2rYd`yKRje0Oo|*FxxAJ#K$6ruUaV!+5{9?|w z=xM<}t0;M8`{Uu);|EuuC-t-6V1yYqTBuhg!zyzywLddw+ylP#5vy!(yz;?s1ZLW= zQtX6pSW9-v1#@is6$afLEByQTTGw{Qh9`_(=o|LC0g*f_kTG#kdq3;Sqgf4hh=yG2 zRxM~Z4LLLTq%vgKnjO_U{bm0V4{wV*^@C~6Z>bk?Mpa%F85as{iw+C^LdoWqJrNK8 zLS<3ik50_Bw^23|jXPwodFFEwOamJ(a3;4;JI`^BoqxgSBE_=?mo8|(#&y4#lld%e zzy=|X*L`0OZ;D4Bd>T{who~d#aZDr3wq*UUzMrC}&YVV*IMpD9JWnkn5^BC~N|@y< zlKFTKIW6yqoYt?y<-(_@56^_dRd^j43a^-qmX8|*|}=EH{3^zVhE zo)6&g=A(+s`K#7RumoYsECJU1Dgfq>{MEqUf$zc%0)srJn+GrnKEwJ|eez4eD1h(6 zaVeU^9x=E3(frlGq;&SPd}u%Y%i$<`8+mY)za5URTu|pexJv}P5a8nk^1lJB<@q_p zaN%={+j9hSJ0ucy5_2SFTKd&b@-^vtVO`QT`W(_JKOT;c5ty#7TgD}xCHyt;S(lXg zDjbuh%&p>+zX4A3zX8lg1?2x3j+D+Gn4;{VKMKwV$28A}W89nJFr!kKH{PUldia=u zap{xN$*_IfNQnLjILb3kuKF;oFdQjeT(jH?A;Y-1v$7mG#;t%GEw~lFE{8T?%2Vb( zI8r+Ow1>9QrybPKcER>@s<_n0xb)A1V_d$v!?Ivpwl&r@@d`LykE?*S%iofw!|rl5_mXFrI09f0w2$+;kzgb_pZL^F?r;_L6 z1lm?YVNg1Gvreys4CSjS3_6uO%aQW>^Okh-4zAlFuZ>`aspR>1>RdP%ZYi8@Ck?>G zaMXFScEbEnC;gv^{9*BF!x6a25*`laT0b8J>i*6xzl$J48)6gyF)lIVl7A1d?st6b zsmGjMz`D)60Zd|CO}cG3VCcMG49t8nzw{};436Uk!ymzs(&;G&pL*zzMtYQQg3qKW z-weQM5&8ET{BHyE(;pX(j~Vj>cL0;jv^-AA-=1e%vxz6^)MvS~xRc~p!?PI*kYFhS`OZ)blL&smY5# ze%0NREWbL*&kRpb29*4al<;|qsh{~xd;c~bKuLj##%Kg z*SVMP2wYpMu7|9R2y>viM};S-{dWP?#5f=Qdnc|lJ^nc6qkq3HVfNg7^zV-lW_tW_ z%SZnnh*6SZ{&?{$cb+%k0JGfk@doAv2y3Ff6)EA?lDIG}ltIgc}#M z!LPm%N5y0P&X82wjo@v8=2dNcR~hdS;IwV^a&X$S<8jD$tgS7El#{PqwA9sHzr=e{ zfd|kpYsLBF#$`T7>~WbV!+VnRSI@*kXf=-YHsT-|l}j8QkC&Fs!^HKKWh?L=TyLkk zd;0=3v|(lG)qcLwHh}pL|me|q{iw#_4V2+_$rqIBSfjRbT z8K$Li0WlKzm3uZdI1XJH% z1k;xH1k=V31XJcS!CVCJqim>?c~WQn0Xx8a&yjq}bB|fanYhNZ z$RpNz=2K=G{(#h(qL3kvSf3})JTNZx&oS`l1+$GTL>z6iI(G>2_iMI4-LC-?7mKWujNB-0iv#qHz1ZEjj3!gF#f_cBFY=8`HSS@_Yf62iA zB6uErn5)iqW|^pZ&+*PanIilO`0NG+;Lm|SS1|3W6wE$L(%+~lJ-HrFwIB3Nn50O{ zoQ+Tc3kF1-ZOWXd*j`_wVW1x627YR}WkJrimAG1i;69?{eI71b_`Is?h56}rzOjra zQQ=cRv91?Wf33)nN38X;4cWZ01<`c<+sgcFzS6_S1!5ZMep^R_&vT_nv*3s+TP~P7 z<_o6os{}Jm+CzD^jpc$FSB(SUGwxS}PkYx1W?a?YAkzTMwyyQCt!S*qR5RQrcK zdBplRg8hN=5%_I_Y0nx1bBxo!S+@zFJYua!$?yFTX2tZ7XC@gS;qE7(4)^g z`mJD=)eC~D<5j^d=hp=@%{K&ded&l`ChbF*I%#h|!IbB{8u?tn|Dxbq;WJD=(_JQ* z>GHcM@>vFLf~iOKLGZcAe>K9CA-+rSeemxU%z4E31>X<lFVF|W@EW;s18n0j6o{73kE4Spf8KG*t~@W~_2X5%6uKK1h9K-!ulX6o=i-l$9xFbFaKUho zd6{6!UMZM5RNH_Ib=M022>f=zl>dWZ+VUsCl;==L{mbBAB$(;U5llT5f|=$O2EPDU z*PR+4poctjd{BLP0hpi%;g}YA#M#1sO889ccLr8t!c;Io{|U#q^YGqzZh7LIjWsQhCE_D=KR@^pF;VC_yal&$8^af*5}0?7e4#C z8rva5d?p;_OW}_-a0%pfet8ZfWymAe`MpT^&G0W3TnoR_z|##q>bC=W$RpNzN-1+S z{(#gNNP7fl3x5{ET1KsPK!!YGEyJ;lcCu~Ep*(LyK z!n}?&0?zKQpydz`@NkHDpodj`WqVkaTfoDm@boz(${v|FR**l~lUYcd=iw^iAs%iZ z9_ry{VvH4})o?cQqRB>nNK8^=WwY>An-{F?6s+pSucCToC78`rmr0d@8x5>%5cyjT z{ze0DGVsF&-fG}>1Mf2MYX&}I;7$X7MlAKE_JA0zwn@e*)BDIyMdoG@GAyBXyA7YeB8hpzNF5<2JUeNowVU8lo8Bz zIgQmBbi!9>&&l{!0HS-kx^&R2|hxZ9IwpP8FYd_Gx+?{Ny~8m9gQ6Wt25{% zt~!HG@GQ#6J+C^0POv(IPH=-E(?%@g*jfXtGw6h`&Y%0aKR%g%&U!6fGnEQw7F;ksEC*!9&gHEtIgHG@iL%!6&>I^!OQD@M}*jq~( zJq{aKok1sjbq1Z_dkmS)23BX#iHtgfPVh5^j5>o(`05Ng!Rib;!N&}FZWN(^7t|Sa z@*6S2;1?QLok1ru>I^!;>I^#hO_@)5!BqxUXV3|MwZXsD!0HS-kx^&R307y&3I6Zx z(}U-=cwlNitxarqqrOGK6Kn5F{3UIxYpRpG=HSV&@qCoeT$OlIAoYPQ9>XrFZmPX8 zodlH0Q}aaP$>{otwtm)q5)t*#JI!_Td3T!2sZY7nh;)D4-K#(^C7H}j;$e5XVn|%n z54O{!ki-e9Ynx|UdD%C15UZRWG_go@rCk|zXE3g(*%x<q2Q%rHb?x z*Xv}bR-ilM|82Wxjl>iL)8@q9O1wWd2~!P4rTE(yxy5~y`*I)UHuq7E>j!#$-#{W~cgSYx9m&^N+KIl8Ak8itzO|*~h1ChhDR1xn%^~Y3X=ycx!-%Ph1>GB?l>7FifOg9@DrCy!x z2+Y4HBCJWLJ5}U#y4<^7e<(#+oo)njX1ec;L*8Kv(>+7vm@dyxpl+>iI_}50=BG*P zTaco!Xo6+6Lx}p$f}?0;k3T{QuJ+xKDmAB zrthf~xvh{3D+%w9PWQ=_bdQ~#YzKu#x^JZDHDt~eOsZAYh2V9GW3l}(KiC?5R}uT^XmW*m&%0-G^&SzsSib-DCapT`nE#f zB8fv!>zkRP?>O{P7adGZ=v$ehkLUJ|#&u0vUt@~C(n;Q0IrRZ1^lePhHwF4iv@(%n z@QxIHwT8Z8kz+gEmZGl_`l_iw2$vN-o}%w|=&QmN+Q+_1IqLgUiawt6dlUGYw7xwl z`rb73aV*sO)Y=2WdOWxkiIiz&@Y$B=3VELnU-#b)kW1ID&Vn3um%@?eoP+06h{$|Q zh12OqMW0T$5bHO~7(qyx-&$M_4Zmyx{qV6=nn8T>2!T4U}9a))3Gkp zktV+ z3c0m90AI^ZfgEipm21P+Q6ANv zpiTJkJBYHn1RUM&QS|C#Jrq}h);RbE!eHohxh!X}t;g`b!sTh~OWr`NxV{yeKAvjN z$I0hT3FCu#(5d%)Jjf0XBfL3G2>a4k^G$f}gVxs6Qs>N%&h++bOytG`%qJ=MUvX^J z62dMmo1(!_@LB)V>YTFU@$m6@z_pLZ+wqHt4Sm$6G1&aV)T*K<{`?R0skp&7(#+|+ z=!%LZ*za(mb_u;2s6BXicE(%wi@xno96BC0ONdye}+ZPBdAX3Lql);>m) z!ym+}1N|zo&ky#=d7y#(_sPc|8V^LO_jy}7$yPX$fU?8g>vw(ct6i&dI{9^ig9^jG zh|8BRYg1drXlr`_k48f8)Mvb z(@MS4nz*9Aw?K}t1k*OnxuK;5(9XM=Nzp+Dyt^XPlzw_02 zeVuRpEUSK%FEeJXUu%VS96Z=|IBM;>Fp#_c9&5LAtTU1~Ve-Mr_!E2~KJPiy+}iiB z`Bny4A@|^%@U(O7m)QI=o6+B%#$|35vO`tykg|?=xFde^pyj!Xb5PB{qnub4+omiV z8`^=?h7J0pdrFVRsor<6v`sanY3F%+LS|kCqk}({M7V#>)aoH+55>a|ClmRlkx2Ll zUiOhlr8VrgN4qET?fATVp#mwXL=Ki7LtcKQ@`4|*(12}GH~1~4fvtl+Ztsdl*T^`TOw1%xa5S$H>N7e-|Qj)>4OXIBU@JyD$71YUZ z?XLXg`?I&lugv{u=da_~M<=)2-Y2zn^|4ir*pmv|4`C168DmD1)(RU*4W$ z7>%CG84z}h_Pu3u%)CO4nE}63BtvHK-T2`L8Zbyz`o2@`yD#edHpZQ|W#h7iIe{&1 z-M--8kb`Z};nTOxb9r*lF-^)mS>OD2CuXCHbxT6#0{LN6{pu5(yeeB*#&<@^XdZEDH2VRc4 z`{unFk37&YE%JJGQUAAH`%PZM&X#|tA3Th`7*S18-;DuZ>FBSP1m^l)pFFDC+p#d+ zFPj(!5BrXlXTX?=Hj2U9c?|oIc}H3WKSFuD=9^(3e(@aa$@3x8deOJ*Fw2Ac5UFzB zF}F#ViMLahDjEJpHa5ku1@ZJTHT+kEU4~6}ftWD!^LSiakhF(L7iI7`%I#pt7kS{b z0V}6Pu%Bb#$W>DcqW+A)pR#9_mbP7dUjGdjMMnF!jUJ9o;;>a*q&gnin-RUjLX>Hd zK*lAbv3+8Rf7{IIXt^c+sWnr0!7XuHe76lIO6M9b~wIvvRzyfK0g@oWt^Yq z`uyQH;@D`n(*93oI%_4TJ5Ek#L(}p)wOjOxy2feV4_J58RY=>PddX|kAF@rmMb_RJ zo5Eh-``#XduRbweCMwvxYpB{S^u~a{^xUt`^*a&A-8|ge&ub?qu4ok!RqfNcpZ#D8!gi&P4idD<2>sr#~ zO6Mo|sh$@`d_UY)lM%Qg68&NLBUQj7v46}D`4T(u* zdTlg&)&I!sUSp+Ch-UX1CB^KNqE%6G8^s+Si=5Q5O^KVREB#B0?a+%?*VkLgJuq8v zC=Atj^I2>xnJStl{p!Z1>b@DEn;=@tiq=)l&Dd`+*$~8du{qIPv3Wa2-dOW8NkSE2 zt#MgyToPj!*BZ>>x6tT+Tn8c5c%J%p&W9V^A0y1QSiaMJ2^`-QkG)6MU2d@L^x(dp0&=$4+?oA%B`<;Lf+~PzMIF=!2HsPDbcZAmBLM zfB4Xky1&f?r3}P3wZUD`j~Nd$=w8ZP+ps zrm1;*bj#V9Rj7=X++h7U-_Dn;kEdo0>pyDj@VwbK*zU8RI!@ciu5agfdwr`N{&GCv zJL)fJ_@Hy#SF4UXk9;ePNw*)nQ0|Oa!KS$DTAcWwqbA@h)INZ>(GqMtZv~gfI~V1> zumCp?3-V%1<1Z|Lj|^SAAmq;I7ws5Z8OyhCrt|?{WibDp{F0Ykd#pRtD)}KdFARmJ zZt-PKw<2d2VAI2$=UcP!KqXv>)Wg@rr~Y6JY*;_V3Vxp1gb85_Ib9GBm-A<+fm$=M zCTwxP%(E?T;*I?>LzJ2u$ISa?-fJyUa-$*FaA??-S>b5h^%o4=(O=mOYlG7~t0yc7 zo{x$u!foAb{EVYcX7nqa6GjHAV|n)Fi9A#X^R`!q$8%eJ+~0*%4Gckw;dpp#e4iZ{ zjx=XcI=bcZ@R{*Y$C}UVGGzl^5DvXm9p%Typ_fX26F3X^Ik92!P$r9dz8xIuWizwV zo|hZH@*HbkPCWF|%{kRRYi+$<)ev6)1uHltUh=_F+}h@MwtThtpQx)?rYI=3f*HE5 zCR$|!;$gq4tI$l(J$nSc8pW`WnGB0uTm3F2|Jf!MqJ@z!+ z?+NY1o~CbhgRU96)mnF*8kBuw7j)$p5;uS)KRXY`Z$ zd5;=Y8${eorw6;Fs|en(gMW?kk#p_ozTYf{U+En#x2l=(5~7Eo;2S%Db+-{O{|(AGa_l z%EzJ-^KFV(K0F+&n($Ouy&-_PMNryWr(0RFIUqIgakyxYe z2)#6Sko`GjQ?3>CdDhP^wStys{rVYJXJg(A^#|+mC)jlY{=z+Fxn0**hd({R{7hur zVL6?_4^Oa2PY)hF!BM|DuPn1G{K1Lci*dKo&mKdmk-Lgo4!<;I+$dk>C0%xqEZZ^u zo~5w&_e_Pozh@8!4?%y#w<&vaadF$W$^9ameUa!U+|)#{L-o^fgZXjEp+}w$zIp;n ztB*wOL5v*Ub%OVO!^6LaKec91*})Ux7fvkpp?tE`^`}pSI-*-XwKEwC1h}WemG2&# z{V!-gzTn7-fxW@gb_7p992{{pI6S|jIj2*vb8}9|S(ep}^gWA%IZ*OGiTmRIQw{pL zWgo|}`8i8Q?G2B6_m4Q-C05c!o44kiKR2h7FO{j;9G32}(=<|?w4$!9q&N}|TZwBE zou+2oP;t_?0wLFokxc7cuResbs79?$w(oV0}1=M;~qZZvv}yXcN#ZVzlZqNPqOx45qk(m zQFo%na^gbLRGjI7UEKes%IP00pAU{;#uNw*3i!P>53JXsmWQ?Un=|Op8*%r+tO>IM zL$El3QyRE95z2XI(YENB!9OTv!$O0~Ugeaj!42<;FV02f@1qFcTRck9J2D%*+UR#$aM6bGP8k@ZP zO{oTKX`PT@F{5a@ky*C9z~@MAHwiD`ts#669}o@&_T{nMxKTdK4IAaZugXoW(_rmR zEsX}>VR>zj?D^`AJG z@|Hx5BQTnpmt#|}G{z=aUSr@b0J@nXl+q-1$fSf*J-a{eM3Tg155`#@t4T6bkgvb- zpbgjXtES?_R<$+sW}zQXAZZ<+WzxrEZxyGx^@du&w3Lxq){T!x)?S?D*LCBYfqwlR zGpN4zXMSqXOS@e#0-4GpZ)0Y%H^Lz=O_O*UgCS=^G+-6vU%ETt)FEe+aPzCK^!$@$ z#NpMu;AoqQ*Hc_^2Behr-4X{YJlw4div>L+4)l4o&l6JE7QQEOnj3Ch-c#D+WWzS* zgZ0nYe3yi_Ax`xT!09L;ada8{078s|t;TwbV&(MLEz{HZ!$chQmTS6Xtla+FyG7b8 zaawC)E0!$BcK=O1o6w+?vR;IOplz+VyYDT|;FLIvCC>6?D_YQp(%P11+tw{OmWCJU ze=!+{-63t9d`X98O!bF8)ZPB%2A&wW$k zoTSTH!&3U(%U+z5bve9q=e4(7 z#PMR{cg~BmJhr;`-hH~*mW4D}M@JE-x@HBA*!7lEnRY6TM4!VeQx;nSTjMb=os)Gr z{H}Xt08!QFK2F5xwaek%Jui;#bN}?>w63V_y|~Xb%7F2XBTi!zcO^ui7dlJ$y4>ii z@nCuVlHQ^@Dd|)p9UZ5omvn+g9E!xG3{H{^ey=^Nv~8ax)or~;8k-WQ25}VquO7RgS0}ZvM<+dF z(&0iej;)-;Uw_gl&r3X2&~iGyBiD<>ACclaQk|Nw)0-u7Q^cpIx96svJ^Urb>TbrS2cx}8i=y0mJ+rylyOTc*1fjzsyja1l82pAet?t#J8pF5FHy z68Xd&A<5qj*H7>t;gcvsJPD36ezXTR3Gy=lYJ|TOm}!#F-C*j4|1vQCEBhf#9Xv=;Z^}_J=X(YA$-0WPNF=qE<=7POd_9n9DK4yq8DpDqkuDo z?@I5cJhA473_h{GGdbVjBZ?y3oE8jzxR1h-(#e}?&4LW&=fe$wV_Hk$Na^A_ z;4>}y9BUYtc5+-{+*-KL3ue0|rPIT>)I;Ba(|TCH)Wd}dRt@7`4@W!6|1}&bole?7 zo%H#kEp@Wp>9%(bFzHlr8J}@kZxi5{?#bdhXoyUgeg$M1w;7nkw1`;t+iDcLTGH5g#;Uh_%flGm<(-0ndf3 z4{jMSi8_h3&FX7(;eQu=ZS!w|8ISTEz$@W19N_>6BA=K(?U`oqiS?K{3s~pzB4CG(m$EjP+&dYmIBjk>bVG*L_Ng1FEjyb{Vl-F zxK90t4S8Zc#(oH_%k~(sZqI%y2GJv40-t)Sf!T&>!@mLRe(?hEMZzC6AgOaOFtVoP zhXGRuM6D6P!-PKxm_)uNJ#L%h#<{r2_^d-xI(alR%MN+-7PcSC=faWF$D&%KTkx~+N$K>E zugfGAGu)GUo^Qf5ljK)lLz!Vd@Jf>3a*_cczp^*U>UrMDnB+wzKQ1MVVlc>WjWrXI;G-%dh5rW|+VIN%E`TelvV|G63Ya=B0!yQ^K5wB+0LK zlrzIuB?CbI#JtF3a~;&A|Ns0K-YX=@uYL>6a6vKv`f6gB7SL+;t`lf zBuDK$>{QB`G%d`;wU&;j@i-vh_^v@0Jg5Pg zN6j1I@-aub7-8PMuxIl;m>9y;dx;89QTvAjDk6V9t}{P(z~$rj>PHA`;`N`TgnyM1 zei~uQv1jMw>#M^EJHU6T@aL@05M~{JQ-v?EhOwZ97;kb)xB_ARqDSHK@m1flZsA$h zw^HQqPYH96D^1jIu8uSOY|8aNq=XM5%=9^v$j5leZ<*O%I8(?+spezqGz<9eDtx)+ za4IE4{o@gy0{?EfeC%?p?@%ei>oakk`sjFm&D99=*PQz=G0ZhFn#7)elJjj64^pw_ z#*I(-O_e&kBzfLVLIm&CY6&@*hEI+Ym+{hM_xDlx8O{=Ui*Sj0J|@T7v^KY3nYZ4H z%6BcHS*@%lKO~FQUc0KbZAkFJUrf^k%I4 z!x9|pt4f|})-4pv(get^fW-Pz4pA)v%qm&P;C>B z7hZy8`_$SnEL!`Lma`B<(N!9b?~>2 zH~^nBXky+Oa5k(l#|HaS`~elikxw3Rw(uEW+oNp5SV20eZM+C_;J7bc!Zv_}ZNLfJ zfD^U}?qM7FskSih*f@N zIyzPOe$SJE;Vu?johGS*LmrM3whBO2lg$7kgOQW8_!w zIm@eh@8)s9+~1$XG9_jnqk^e}D^uj(446GT}b(>x{&hcW!;ukU5o_-#PZeU&phz#0rsV}f_eR3!HoB)V6Iwk70h&= zHu!r5bLIK4V5a|9!PLWvFVo^m9arRusV5+q`QW~&r{KYL!LTs6h3vX5lo$2siZu0J}#I#w;KFif~o(Hf~oVMUB^RQs%HbA9b-pLK2$=Id#?68K{}fC;U4j{x-$hcU7?^Uzw0VSJ zm3P5xdt(gD)nm%9g}+(wPvAcwnDxvsWwyfqsbIFLM+EPL|0}^y!T+^jKG|WIai50Y zE|^bnUK0FA_*3BYUe%uppFCo{S2gcTs3!zJ&%h;&E5Aps@W~_ANkc`~mG0K6%7?zv;cg z=l;E~3ub#iAec|1<{*wvw^R7!5$kjrpXI}+X1vECW?lQ?G%h#v@M!`0440*)a!oO7b&G7NLpwh#B!|z+DlTXU#BaXJYLHOhm>$Di3@_cf)kn)T02eeW6 z zTP>J6+5}Vg8o^BSR>8F8Ho>%UhTwbPkAk!L;|yYVqJHv-^?b$w*5_)d`2b|dBi8d7 z-uE*ub>3p&LSS8Iijd|AP#%sEKg24Lxn-am4Efq{1 za|KhkDnmR{U=rsDU&RBqzlcAe2pn~?+=#Pe|1a%7%xxrbeN?+Hk92>f@?2WwyXCGq9@P8ZbaKi!$U9XA6IU@EMoo zZr9=uh{Gu5$s^7dzAE!NFhJMCQHDI?Y~ic6E%IL$8S;p=9tYTFMS(WKQI8`yTlfej z>aGa5fX09_;B?;^3rs$F#JZf#x|=34asP!031HvbdSob59U&*`5?{HiM(N;aisxp`PIrEloTn&R? zK;uD`aKw~t7R>RIj(qC-mSCpyUBOIWwO7c{E~>McInYcv#wCw9Tlkj<|9bc;zt;kQ zSYDJTk2qWS4zO;YWKo7ZV%TM=el>fRvu7x3>fa0pnB)ei}u zJYrq`s?4SQ1C&1ve?Y3t=XjXqm~N~_@>ap=o{aik1Ewt3ILW6DRc^r4t;Q~3ra4Ar z7%w7t9{gzrR&C=_FhHvBATD{T?+Cw#{Ueol-|c4wfr{Y@fN6h;;Dr6)C+r7injw*4 zJe6PYX}|hS5!}Om@Kfz?L>&7J`~fwQVOsz|`|okzrmR z5$ph~dtt~>=ii0TxbF#OTs60c49o1lgirZwpJ)HK{Fo;Q_9NqA1FJba;ub-Ew(zNc zo?z-z8QHDCV3#QIz1p`_y3T7KTAo%ir-kVH}OPl%5y4G_- zF!c;TB=U=a1AI4)E=Qnby66 z`F7Kf4Edi4E{Du740)d6!L%s9Q!w-Rs$klANN^!=7UZ;TJgbA4_M9%b0{9HUwC5bb zte>fZna480{|3xAuBZpeSS)MeS-_Qoi&3e3U0PcYN^L@>+$Gr>%20OB()-^dywnDX3{lKgVu zpkT`LJP$2DO)&F#nPA$vKrroGBbc`F+z!U2{%;DN4}7O!>VH5m%m3$snMXRtrJfyv zspmz(fYu)bvwrv{8Rcmk-z3vTeXxx65u2Ogq;KW?J76%(R{q%)GY?rv4WMR{_5$nEKxk z%rfj0OglN)(9Y@bIgV?aa|Ki9Xu(YPY{9j_Y}1sd{tE@uo{I%DZiV0m;41`E{zrnD zua^WfzxxGK&k@1Y^N!#~;P(Yn&u4<+Spkfd${zSb1eYSO&A4VS#~;vz@>@n8aklXJ z&H&@`P1kvX`S#t_g87@g$l$jjzMiix6+U^ydcL}vGIBq)T4cy0*7s9C6#ilOe9wS3 z5U(-x?-xFK#9IFm;Sa`d*E@o&aeDa93 z&9_r#1^$5U5gGD`vxWa7;d74gxZq#G-zu2D zka=D3LHGv@{s!2g+s50%Cy!X$PrXcw^N!Z2EixKTpK(~ z;!;n@!1pljLi_PM_>UMmx#v0K zl1Hp{K5fYFGVo)JE6*>uA35WaN374n%tYGc^9}YK!A0yN33mFDtx}3 zzCtkPP24}6`Z+JUQ84FFYYhIAhW^`xPad(>znwB%5CUx#8S;p;h5uXOb8hu}!F%Ap zB$)H1R|In|_Nu}Et6;t@|E6Hh#r|Q)d?=XnvX2dZJM7T)?niv)mpo!^KlPH&`PyK? zw1;P~ku-p$s^V}ryBC527ZolufZP>&ts#0@`&{_rkjM%xBYJsycz!2 z4ZI6+biTePeDa934cmp!`Q2{?bF6q)Fz0$N82sIW`PIV_!JO;8Etqq+4+L{A_lbdb z8}{^{~C1ZGN~6n zdBoa=Hbeeq1Mg>CJ`?~wEPV2a_4BE1!spiwPiYzWzccVb#L+hVN%-UuYa5PGW)c2? z-WD11i1o9xHxbq{pNb55#9AgR%WFTJZ)OW-{SFa)8vJ1f{~hX-^|bSZPad(hjdNMH zNzVOd3FcgPu7NuZJ&S}-9g*J| z+QZ)vnJmZE=A8W% z0~b&yAHsnCBz*FS^;zbJ4EeVVJc4nhJ$x*D@`!akj-rgrJu=X?SYPB3>p2PA9QkY~ z0ob9}{SdTlzNiJtfYa-K4C{5j5x@lwIkHylc(Q7p8JIeX;V47huHfnLCm47zu+GbQ z!Y7Yd=cRx$u#6U{5 zQg%u@s;oq(Dyuo3j4G>(JPHKy?9rr;4zh+>r zy=$3L1M{9y^B*?wegkt&Tg#}gf+g>(4Zb=DTKESIegWpgI_?|;bIn%sA2TrL*qT40 ze-f7)c&&lA8u(2Eqq-7$6h=9c*spBljl{lW!&VaekB#^w2hOG-NVU&w536>PGH{83XBoJ{z>A2bJ*d7fxXs|NHSh)l-)G04cu=Xl+8o1oR3k_Ur;AR7J%~0#S-N5%4c(Z}kZ>ZStq``m2z`G5+-@sf0 z)M*_vu*Kg~(HSr>*YPyJ(7=55s`=9mtbV&i&wPVlWniw?>A0&6%xAKiztO;(4E(Tx zw;H(Jz`G3mnt|1vL2TI;Nu3)z;C9uXRv`s88~F%DF!YzaJhjO8o1WL z%?4g$;M)y+kAXKEnCm>+&L<80jDdF>c)x+)BzEwF4?1RG3v&V60TaaMxwZoU;cntARHfc$0x2CLZJI-)i7?1Mf2MYX&}I;7;PP zo}SN$Lmti=2t3}y)}+=Om$${L;kUJTeuGAh%dqEUtZ`D}i%|1p=t(`U8s9hdSWg|v z_I@%INvX6csD2^VB^!0RZjmODlSk;0UbmjaBAS#`(4!lrmYCOz(io9wKf0f##zdz& zSv1uP%{Zx@u(!ymay@IvY|-3|pf^paomOpJkgh$L3X?rMO~dIX$i96tneM&YEQ)T1 zN$2iUCK3Zdui9iB=##d@m~k>~7&7{*OpPwR>Pj=X^ht4=cs-j0$E1^K^Tw=H+hoW( zS;WMsmZqkA9oJIR;jnhHM7&`yHI_H(oh+Un7nN-iJ-JuOlA8LZYMh*8@FXdYiE8Lf zUh+g+m*|dfVK?jL%j;HP#9fV(|5{_%th&BQnmh&>Ocas* zG(~*v;nq$O*Ut)cO@^8!DI{_0bLDIu?9gALYOo!fDdu!9d6n zm&%3LO1y9Tsu1Rw!fOGz38GJ@dk1*3LMmsfv>Wzut-lJGx5~W6_EIVObh;y8+~eSD zqD^$IBB#^kJHO^$WzHa(Pk*|r@=sp!Wo$hl0 z4O$33^^raTATDJ9^vq1WO9#ISj(OuX>OYI?mhiQ{Vyt0Zjj$%lkxqx4sqf)g$#%*y zN$cY~d!|0Fzdfoncz?9MnJM~8Eo$jww(mjTBKZ8sa+~?qQKHf-4 z_a>|p4aRj%I$gd4YNopZa=+F>@O8RbkTdh!d9h`!MZ_w|Tp)6+--)76=XW;Nq)rE4 zlTP=Vlys{gca0W;uhZo>KxVqlmsnOiu2;d8!SNc?y)h--UqfHIe)O*?>F(|&UA_lv zrdxbzGTm85x^JYUI{}0JC_e;*bbk2^lo;ZQ=H%kr2b8rYrbXg4BotBdB?U0+xgoJdu=R(d*_q8R-{KAApx>u&?dky-Kl>}*h z^HTKPSC#yID~B}YSZ{n6)y&7=pl>bsnsh#Xl#*@(o-66yp((4={a#ACk5ysJ_j%=a zxyUiye@#jE?$eTGiOb3+ru}M4y3axGSqcd0boZvDySB#r9<~Z{m2f)0M@1h@QnV4B zgKPSlw7z#!^sTPL`;RcF3WD?Dw7vltC-C3WO>T|r*$$Q>=7BUCLd2$=PK(zyJ`-}p zrDTH2mwNS71$-5pPM6OQ%yicx-GEjia`4oQg8H#Ec~oi6)yH@Oz?ePAVI$lcJ$ zeHkY;o#S{EK5y#z=NF$h`P_)(6f2hZH(XqN-jpehbMDlVVvkcb@GBRU&$ji8ZAxeN z{fO0z`Y^(~7YJeR-v?FlbA7?Ccwj6}Cam;5UQwJ;RX2Fk-I0tt*G{&JL*Y%^A{pN# zED1ZK_smB8iT(}O3ojHNSC_S+GLrGF4gRy;sdfD$8Fz0O(&^^qbn<|_x|%iz%RX(Z zTAeYq&cqAwS8YeBbDi`t3@Gx>Ry@wL6^q=xcBL<4?5YxXzwP=qxH~>kr(ll{9>r;h z+akk*AHZK)J*ccR9_~a20#W<@cst$$DhiB7+(dxwOEChlqsToH-3WoBDA+_A)eM@@@ABjRfd_&%PTHQrtv zm>XDcTV-#@fin<&V!(b&Suqhp?ha?<?-m2q;na9zZsl zV6s6B9I#0U7%FH8NU>sb4?zIG?wifvH5w53%LskPV>&?y#`_R0`?a{lN4zb9+fyWaWMw=T18v-V_Wmi4|%*$L70r$D;j z%1qp}bNzt_(za(Oofy9G%)IG3(Py4qqS61}Puu?Nj`FnKe%n7Xf8>nt`!Rp{fQWxz zdFrw9l+RC&TfQ}VK0fQo>P($+B$j_9mU9Fjq)c$XK^gu-Y~LZP6IHsq_E`UW3);?i z-niZU2IaBq?zIlHY`M#4KbUSi*6$gxqt-jhuaJ*@HdzN$c!l-0@>g5GqkpXbJ(pZG zH0QOLGjv94MXuAH8EOysmUTMQ`#IBt@aL{{rYBFi1n*Ps-&(Wus_;uO`-Y8`GWCvrN>kZ7*ZQ$4 zMFH{|ekf-1qn?g4>g}|YT>ri{YxbQ!C(R#v^Ughcnse@tMTTySM%&gDv~8VnUu;K3 zc6PKSub`!5rth-RSFZWHJto@LZhc?bOP`p8*0YA#A0DtHoVG8VdMups*~zr+#kvi5 z_>{Q)54fJB z@vd$$wCN`Dbx5X~3#@me1i<_Fyg?_y| z|GT+x=P-@wXTTwE{_=qJ4<ayFw?=xW~jC z)mzWVR`-_^YJ{?Tmr+WD5dVDQ+dXn`C3xZ(_W%}5KQ4A$JLIneo+sCBljcz|NIu&Z_8?P%b zV+wY{r#GeM9EiEYfqU#b+?TU2W*t$r@<$%`?u||KhxagvLk#D?fm%dEQC%$D5v%Zz z#j&g`A>!ZoyRFfS)i-tLRSb$`=I_LpcR7gKV<#rDJO9?rmyHi8JNHs^(v(*#E(_QO#`|;If42Kct-~+~Ry3bzYesp=ng@f$A zGw`)sd(9p8^u81OS|^y^6wI;VkMNn_S`1Z9eG{hJBdvRCjA6Cgm>J?Hlu?Sa3!axL z<2u1BUG2ep;(r;YZFm0oL+pd)`wk}@%gWldzTc+LZ{6*8zm~jh)N4P?K89keDPY7! z=`yDB^T?fk-z8tlm=ebSg=A$%*XLzBA*VjOFDiESvM*K^FfX{6$M#uHa`V8>K2GwY zOVVyAu-8nrto^L5B5OqYR6EVNb`idk+jlL>jt?D=J?B^=GGT2|Ok1oyWj%{9bC+j^HpI8@;d1L5Dt_TjtS{TDme*1A(|cs~bE zu4@+ANr|^+CG9LfFynasXBaa>dUjCH{p%vkIF0XqpV$>H*sv25e;}(*zZ~mxrZLhk z*_U8> z3)&w1@+8}_1AQ&jINFLkM7qaZ+x8a(5=zi;UruzF9}#<>|9-b8jmSFB4eetEz3rS6 zv3L0IU+MSVbGbWchT5CmPBmg<(Ct!S`ucrtk9y7d5Z5=&dX2I7K9BEwZ;ehpxg|CY zpG_ZOf9X}r2fy{AzDd3r&&2YdjpaNWt9ZhPw!MuJB1xY{|IoLuFET3sr!oTPJRP$K za>RaKDU7nyqx-CaNeNLWT=2|)=8aB?R)lT8^>d!h|542DgC*}1KI^9pd-}jkEWqbC zEWk9`(3q)?A$}d%$KPWK#)oFk$`8$77?KtH`~~x%h7+Okrs~jwhUO68bicT|D(r)_ zVDCfU1Trkb_MqBCo@V~v`D%PU><_;i8)rqF50 zi2qZ^Kjo`FbQ~;WkNH=A#g~6Dmh%oexfc+z-$9#oiR^_6^qM=`4Hr^dyW_X;ufr?op4bJfjEIo08E^M?33% zQ?B&oCatT?3XDsY0rk94UUP10Rv$D2SROt-0BgUdwaA67tKBA`PFXLKbdnP7{lRE< zcJq$)zAMKhT3g9(UmtUl`VCCOKxjRu;!fv6Ipo(Woy5rndvUq!Q4gX`a& z5BFp@BgIE~rpUS}*&dBi?Gc7{`x7^1*#{ojxxQ<(^~D8ulo)#o9`o4&t_A14TGjn#wzq0HpoGQ4$ zJ&=0bQmYlYrLOdqS5l`%2 zlEj=3byM^&%|9N?IUch0|G^k{oN5T z@z!qhNo8GidDB^|p{oweG81Fbhf5am_siK8-Woj*^Gn1(s3Ixf_FwIUmIeHuQJrPLye2iO<;)L!nACFPr_=>BO9py32aJ zt-p!QL`^6kEbq7J-~*rEiWbx9-+c75m~GoN=phG^*G`$ye-8h$e2{ zIyy7_X>3Ous^HV8f8}uA{@_AzY;t`0Cu2FC>K0qwlJ&)pk2OO>C6P#le@#=LHFlqQ zgT|LcMwawhQ+9p3J+Qd)!JGQN+RsN3Ku(YT=arzMp*m$U~_Qui4q}MHd8X zcJ(VOYesj+dt8PrdTjlO&FdrcM!a1!JkhDWbfwyVqJhOn7N_1`I5GiS6GfYCJ25BA z_Esp`@4*>+Poo91;qEH8lRFP5pay+A)<<6d?U9bu*LO$kg7vGgdN{?lYWs(LGSWVB zq}l1edBjx*asPSUW>1T1uC2y=f_bK4LETauszc?C-MSj)n#H`YL(5wT#pbY&x1OPy zH_V(hd3x#O*^{rGRf?&qv~cRoN!ML_?c_OUmxm>{x^ykQq;a4 zRfs7j=Q6!Nwm>!f4%)>15yxLXWJmc0`^wKhRzA41e2`O~?B3xye&6i0M0bHVd&N2K zUdrswzB#*Noox^93>@u<{bSnH?fLs-U-+X5n~#i69e>rhy?s-C(G6|mM;-7xhp{!5 zd)jgA)vfy?+c8)qxyzJ+CF$#)`TK$PAB=tXv{lxipqD9LrW@C69J;h9K|u z05>a`W+sqa7p+N4%@4(*!?Fw3=jDwKljzZv(KpGtoJrmsI{ zrBmwqt2x=74`h|XodqP}wa>6lgP7@1-0|{nv0denq<*(@)Z87|8qGi18Jm`jrGN63 zGfu=f6DAKS0gO2;-brhllY1;DE?JaE|;o^e#Arw?wr|3tbR zr$5NYC|%Hha}H;`S8cq7bjaN3%LyaCKSHjrDyOqPa%l&8pzVKs_edK9cF@7bItFYs z{oQ@qk2GI>)o(aio8qP!{- zWBNRNjxC(o?aXkTXu^ZLoB)Pbjq=sZ$Iy-`Av8QYx@7#>4&CO5QRn)asw=DK-&T$3 zxUy+!V>2#LIqqpHu#D4>`_g`OePi=d-{QvdC=~HO68LT#CKTq;)y*$f(-1$K*4`K)RVkLC)gYBPha`pu({9nu4)7(;HmDT3V8`>x8 zFTL`m%W{t5O63MV9qnIvqc7(V_s!rY;DdiJn8arI}f@I_z#0(hXm&#}yzvwxo8P8%5PrYAdXR(8RidD+d|M(-I# z?Twqm&#@0}jSj@b!8Hw*cw2c_i?rM=qAf9d0LDVw#<~X^(d$+mst-S@`ro_ZCt~?O zW5$o|p7OUC#)+TC?EcQ12^CJ((I3Z_o!Z@h-}+U1E>ArXZQnCAHQQ;=c`UZaNevBc zi8}t-ld!qocVqO=0|#X#Pn}Uwp5WfL6wRp3zj||Ex_@`_kk~t))O_hBjN!YJBX&pB z$?&&UpzOa#TjE1<>XCj z$3;FdD;3xI%af1HPQCg1yz5&|T%TI-oBqYK9xtBNTvBjfwBX*ZJsY+owQ#ISKc~R| zz?VnEbVqu$;DMxb^tKv)0q9Y=$i=zL$mD1Lxt^mSKL|Rf1u@ht9VY%S03*J z4Rl@%y@9;3cjC^mTMzmF9lLr!mYu%rP51XUEDJfL3_aqcUYdE_k5%RL=bYp?_i$aAb@La9zLH{B zb^XXtv@Lg|{WoVvwe@$}>-u@4vb?dpVm_X4o?ngK4Qv3;s~#U(T)r@ry=3^3OfEMS z3UyhJ19Oazv;TXfZbvW{9LEk9=AmOw*1-qbKWRT4u>JOcBSY^D9chkcBs&*kJLB_P z^YWTU4DdU1lRHjD>IZK2Mg9Khw4sha;7oIz3lnnhaOS4icR3v??lQ3?qkqMPfwJM* zPgUe>`~*J`@NVzC@EdAONXq|hEa$iEk8i4Ge_zwsN!YzZR^qR*6N-zgzFc0>*Y}ly)k6wv z3OiR~LuJH+?@mcad}}@Jd3#sViRbzSH7@5b=Mj8kxB(|PVN(7K}_ zD>a&x63KLbdke3MMU#D4#$B1-AH&uZKXwsTei$3#O!;%nv!C|AZv;jR%nb+k?i-M_ z>!>>~jLhF1Sa;a%M|R>J{<~A}w)T{5xhWAl!iial)`zNc{BB=5hTp-H6Zam)&t?r)^2ovaCePD{?&4~3)d&$7qrCpcLXTRSmF6g=@K`6<@# z)K9b%@`i=-#)PD;*nJ08T%@irM#+LUE6a{P^SOIl5q=pPlnFa3M&Sns$M4&gRP&C)#k%mRP})eyg1)hkSBPtmfV~an0R10@DRHv=gEg zS&__T@8z*UC7z7r?>u^7FURC)MYbB2Lq`1(=B>kXD2wp?#R$)d|3wh}@`L4n32+mU z8wH_#A?q*9V&_Fk6O(bzq}E@yed5HHJN)(iu|c0~57?Eu%VOJ7^Ks|y5SFxRKE@At z_-&=XJD44P3xUX}YYsb3b~Ft=`?b*M?MH^Dj*sHkKPVk!DoEe}{ha^84>ax5Le^Uh zg?FLn=BB+i;L?aw;|$Mv6(^_L?mnb5s^qn_hDh|aw42>6NDz@Iep%S@2dmS*r{=mT z&ZwCK`7^YCU{eBq@Wqn`j~_o>kh3*5-H+r{{X=ErW0ACh6@K>uAlx}EKf>RK-L1#I z_(c3qVs-)|{DL{^UCYOqtoGHk<6QdyYk% zk2^7ylsx$>dy=z$mAmINGWjO|MhCYFU+>sakZ4zB^}&s-+Wo)D&;1N_Kl0jhFW7ys zThYhZ-Sho>(R;_AVf;PH_5Yl!kS}-dxWM0egJq}ny%;8T?8u&D9hs0i{)*h8Z$DVm ziQDS_iI+LD2{md)>x$gft&^Ord_13kGdb_;J~%4kFL?58w;|vJ7BX(%{3I*s^JI4> z!ya_OlkcET)vvcmhBv>TXW}+-2p8TXwk-em^?ZlyYt=@>Sm>+v+Hcbb%S+C|+k@?- z;^KteNp@}L9|NtE_gxajgPKy+mmGK2{dRg{);SZCx!bige0Ppp9PW5639rg&-7%!Y z>EDTsuh%y3z?$Q5@);s`ShHgjw!ASMnjqG%I@{`B-4+;T&)g2mFXoO=w+$ip#?9L*IG*)d;wUdUNqFyK*)#?H(~_s!)KDe6Zm^NE!B^CDfIhw!lfi-as28*JD)#Gau$7JlqZ?4Oa2%c-6ragTVy z=0GfrXGqjsv~mV+aWaxVJ{H~|D}M`h+%)h}8Hg{!Li|Xm(C5!<%-fWgmoRWc+K^9< z969yp$B*~T=W_;FJ~~&bNoZchn#Es3pTZ`LjnPmNh2Em}hqHQtj zDG44cfm+_cro`~-ScyH%ab^^B46j|`tWTI|Uz*w8*EeuSU+ip68{C(P_%hO!F?FM; zy3G%02TzV+s{VG&9-Mtu$d{Jqi>!~%O=?6jXFp12X87=Vp&Wd-l4<`+T=3_W$i6{66;SFvecA6Win$?<>FXSb0Wg`H+E!2CD}@ z`wTkfpHhZRgzOcLzhzIt?3)I;Z9STqee&&CL7-1lU`@qBs=i&k}Wl(RFoXF7MC-SLzQuVfJN zv{e5R|LTw5LShwd5872_PD@F7x_f_=(;h1crxyg4+G%+ucS2)&AA7a?cMc+ttwhwb}kRlh`RZf0kv}2jGeX{%X42(qm zYp^K77JoGV8mD}KvpwXtf27;GFMnMuXKk!_c*t%3;fL9Uqr>n>BDaP!a_)=e<8hjy z@ZCMzincy{q(JSfqdiB4MnR|tWvz8=pgFDB@4X+J@P79u$?k*UeR?1KE~oa^{o#vO zx3%mDU$ifL;jwT=XL!iNe9m{l68GuAQruuyHPqCUR#x~(N-HkKKNOq6=7v)KiWZM1 zdf1q_deWrvp-5#@!$Lf(&`_6k?bV^`g^gL!>}Yn==&Uj0vgTD?aYb}YWzNV@?x-=N zvekbcgwPoIyZRjUzs;pn`M=HA&zxMEUoi8!Y1hx1Tsm#)tjQ($(`HW0J~zK$>ckv* zDqQb_=+Ry8f~e6P_W0igl#n{cpLEoEEyC-EAyOn+l@+v~Pm=T0dRFx;)yR*3X$ZN7sh8<`QkVSE+39*5%WJ-)UUwsnNP+eum6LHakc2QSU*gQ{Cp#hVv_n51j&{o7C_U-3jZvTeHE`7b5gfK3mHuP!bsl~ROrag( z`EbmegR(Oo`C-8L#|p*st2~sR(&crvkS_f%!7=`gw?pYzY9L4Cp#_RX@|aU z&(8p}&oFNxAc504dA^vF;1Afcal0OzRQg z>jZyj=o9N}rxJmVDho2A+c5t-p3+kpIc~9x^e4elbs;%8>NmrYXC8h5r~5C<%R74V zZ^2P|vd{65_UZG^i}qP2N>BP#;Hgia557?U8*sdiOzR~$owr{D>-y{XTQJ5aF zZexE2rYZ8r;jV(C{w0QeVqHIZz&ua=0$}!W2ku6LzX|waaMW7{9D+}sb-)zHCFXS^ zztP}{bsfH7@Wg#Y|0Q7BXWT=E{&7Q}SohxxnGp!n)uQW)oE34;u?zwxK>v8)l6zv$2`+#zL~cWoK7nYJRXj9dm|jBCp&Aw z(+>R`;ArP09EJMC>;tru4&xUIjsjDc{1{*^Yl*KCo^kVl^|h`8rjRGrcD@6w>!b}> z+xZDF?NguQz*URJh8U(N8lWA)JZ`^#wAVz_z%I;NkSNxm}3a35`!l`2b=?U z12B`LKED#jyutJFEyfh`#9T{|(r;xU&o>(DYkD6r&y#-u;9Kw=xPfQ@y6l<2dQ8h< z!+=nqxDh_}*8`6hyx-6Pr9_Wo836-CzCyOkrGNo$d#~ zdUuo=6fxp7=62rd124+jBiIr6>F3tcZJ# zHklU3GYZcUYdfr`Y&hDV4o9I5G5a9-DmdNFZvm!IM~f~O+c(ptuh)m>I7zJ66}JO3 zU$nz^uGiHofNeOYdoLV?I>bqEjPr>26*tN{KFGIzlWXea2(DYzrKRX^UghRd77F7>=gMFM-oz$O>Sc z)&sy4>S)nvWq@E>^e=&9S_R@$zYtE3pN+s@hGV*1^H8Wmto!U(r z#)vL$^4d}umzeVe`5L%n!Oid~)FIaW;@c!4MoWB;X4pZLdc>G3}YnCEGq^FO60o8)Mdeh7|n5bTP} zx}osA7G2(25R6Oz8aT#%jvO5Ix4)s|jzXT8bwoQWVT3;URlt?- zss9nMZl9k3^Zt=~=is3A`vK^2={jJjDLci$>A()0xgJAMi7rA@Fy(c`|6XskPmw>vrF~c{;13&@aO`h=AJmE4=xWW@= zn~qDsR~-)k1=M&Hrvj>C;VMc z_&!hgeouI{C;Xr%yv7s$o+tc$Pxui}nB!Dj0&3hb!yNbG5>WGi8Rl9bE&;WsGQ(V# z#3j&e{NnZM7e5IUP;-2o3aI-7GtBulE&;WEHN%`s;}THo1T&lx4*&(!92lnpYQ1NM z2gCzPpJRDk0&4Cv!(6MyC7|X^GdwsR01BwNBu)j?9A$<%m&GNZ=36s-VLSj7Q0w+M z6;SsEW;hfN00n$uPndH}TmoJDiY^yW_aWx_;qd@aK&`XlRKPbP9#H2o#TgP%zc0m! zK-ayr%LUZ>-aMZf4*&&xKk$UtdcqHR!Vi1G>pWqu1>zF${V*N?3i#T(W_EtRC)L*( zJJ--)>*C5(3&Z9WWSBL^R`3lCt;d?z{vjmL) zQ_uO$p76__@BvTweNXsvPndTm?4?`{rQx3SQe%i=`rLun!thr;VZG}>9iDIYoNw`j z*LuQFAe@bOPr#+&w?lq^ObhLCCteG~|K$mDcU}w6|F~D{fl^cSJzrqvdJC}#y9B0xr{H|Aua20SR(n-TT$wH6*ot`kiJ*I`}KIsX+=n22= z3G>@xS{T2NG2}CRfhT;KCp;Em&f2`wPQxC@)t>WT^MtEC;bu?xTb}SEp717wxe8{# zO2c|=N4M|{A9oyiev&#r({~bKEi4b;%{vDEcDOYBHkHI%8xfwr*b}}S;bGvpl1an* zY!bq3-#4i6jlLNOvp>JA!e8_88)8hKE5S5hnR+)apc*$)FBGKHx`iL|okn;L z&b_Jfx73%?7XcBbpXmwn|1Pxfe7PsQ*b~0j6Mo7Qe$f*?;tBr)Vcva@QThA2kKg6e z!t^ipgfI1kuSS^le}#&FhwrPN^L3u^ou2R`2&W_d9dK#BZ~A`XInQry@h<&&b$+?8 z!*l*4gxNm6uFl`-`zOLI&rp@0mA-Rv@!7;KSLavxvJqx`a8&p^zNrY*0&}M}&G%j3 zR}ij4_}40Yzpt9gBCL-lPxwAh_=leGGYB(%I?lJhL6}2UnuLAx_%6ul^O^wWSK?6D z09Somb)8`RN29N*wz9Fb0{=`|ihqf%yv2tHrj*{|CVU+VdRB>y>5J>B7r&`@z%^Ch>T6iYH^WsomGUKPP4)3G19*c*W#dv`Wo><_ z{Qo{Of!r)EtiBCQJzm*XdQJ7x$qSmBmiihSr!K&AyLEM7yvfzit8X^A`nvk+t_R8V zV`F^IY+-HrE!8SRc!!4(0d`9lR4?WeX(+y~47|#sZmH4+U*G7fZeEC&+s$9lToW$_ zK37w-z&CGZW%+`c%}t9cn^kF8E0v3yn(%+5sNizGLQ3(l)70GcXxqZ_Qp7E&Trjz! zbWtO|$5HKTtS_C{fM?yBYDyax_--q1XlkB3Yvxo`z%*8jNnF1`)fF?_#7F4r-4xD} za(U&gi{>{~yYN0q>ihf%lo<%jTM^p7Y z6sUaug3@|8)?m*k%kjJ*Pb&M3P1QAMXmO%q(fm3#aHP!_x42rh^Q)?=7nG`x0jX%} zn&`5sR~wbGOlFqljfTu4J}Xs+e*jiznSG-)sK?T(>V=cKGDHIZU|d?Ys7d`lgd2-& zc_maetF8wA8@j7qDuOR0?8c~$>ZVtUO6htZjp{{cohlY`#3v>7yJ~!;wblI0PkG}) z^isT!snTR>nyRZ+H1*aNBNk0HRpJwFQx4LUwEC#5xY<@0=tn;I6( zW4RYDZfL43n=aj-932ef2BIg(heA zlbRaUV==;^w{i4w%jEw5Kf3i2ere9kIcU1jwKb2P;pCW zAB)(fo2!BJP>c`pEJBZ~nLp2mf1$^<#07#zPPb50Wi@WJ6z?ah?rynsVJ(J~g>?i8jpa=Xt4kNxR|AySoB07J89n2akyXPKDxem_-uya19lrS% zlp3Q0r;15@3qwQcBsA!*$fZq7WG>*cp%jBd?I}p@F#ru6dp#=K7lVD;jg1X32da*M=H%X=dGy1BB}_i#HV_ z))E(RM=BlnSQM@!iK(md08AUxgs1K61T)P`1=qkIXJAzp#GMOHxPZrEmHwm5xzf3S~tNM{`<QC^f}wLrbjT5FojhQj)_cIr4>@A3QwXeeJ_e=^ zIbyBzH{ml-_x}>ir~mowHtLtdF9L6^!~t@Z@Z^Yt!c&j>ytdPDPV4hmT=L|IwSKXo z!?r>la>QDvU3j*Uod!NAm^YrCg8u@47HzVDL%1(Uo8*Xt!p}k2T15>!af0~NAx9h( zp6B#f#9!sp&mkk@CvXCA1|0d}@FRkGjntR}p7=_GPXxBu;UJUX7?&JzPX76%N-wQ$rSM;sKM^oIbvP^ znbcX11BBJexa5fSJe3Ws=c(_D4mn~yPi+vMb-*^D)BTC?UwB9UJ*93X#$qYgP@-S7S? zJpW@yjfc?TT=#|W#M6NFypx77?T{nZ^A6*yJiyO1aIq0rjh~21PK}?-03eBQmaK(X zeU?qu72Sr1BA71x6v5P;BbZ%gu3*}us>R745`|-2a>RNqlmcvVVFFR>A}Ej}4ho+S z%(%)nuysEUkPl3big{3RDhh-FL| zM$7_2LU0zwZHh`u#s}uZTCHezta!l1NZw}^xLDQm5*Mp_HrJnvU7piJ4J^au}=3s;n^N*ss95UAm0<79C1+iI)wGLQ0qOEg`8UN z$vDH`hFM0g>l&%gh6dRtJUQZ^@H>S65dJQ~?1Os^+>AJS+~$9K&^|e0J#H_d&iyz* z{w_M?i1nDZ3}HRyBp`pZLykDu*BBek@dxK9Hk{R8L3f;|aYzE39^V+&1srX@0)H5szAkJ=+-1ZEK>wdx9uMZPmWl(?M&)O+ukHPE;(8-by>gG!!EDp zXy}k54hnBm=Mh&Y7ar}9BMu6$%Dc|h3Bl8AV^z1(mUs=UG*^e$(#mr&^QPO9N=xQS zRhA{L4v%_`F&{X6fXg=urtVt7%>RpmcfeQcRp_UnPpEr;;8DQ2aJ0iT^8_<5Ulx2l z{1U<6fzL4YnfEz@StkDXCwZ22fne${6dVG-%+PsSFzbxh*y2P4QSAqI$PovH=Ow58 zZ@}lALHuj@nQ#^x2!!P%PmVY!d^WJvh67|L9CgSM2itIfjDfS(E9m<@JnE1m4ho+O zY(0hpM9o>yAx9h({$pUq?St}70Ja{-0dfkCJUQZ^@c$5=`gy?C1{@&gAWZ!{!9n2* z5!QL&wWJO?Vx5P9!ViaEWaz6k4D`tnYyD}|k^C?YZIUC_`Bd{Dc*ZNHJ_jU7RP@Oa z2Zf&~Jlnw42EI-(*GjVxM~_i_K8NX&Bi3V-n&ZIpzpCaK`ge&wIby9pmpV`40C`Mw z$PovHFGJYk%_3y8=#&W#3ZH?nm5u{sFr4noq%@yGd^-*h8%~e^iNs6Dy3YZmpXZJz zstp5Em(7JdZTw6yZ9glRX+AIb5AfO6sn59E1t-AYC75;&2xi_@8-_mZyeB-@heKIj z@Cm@`8UYu9Q+*kjb-z?}5Y6|HU_R&dBf%l?KNkE9{O1L~4F7$>r{HrcWm+%5UniL5 zR%1JO=11ML1G5fzAF9d-{#SyJ!++J__X%cM-!k}Nz`8B5zG#OWv2Gg?>iif7$cJ#$ zAx9h({)F(CApe=bdQ4FL6#C?d^_Y-Noi-dOQg(90-NqJad)%92x?`Y1tlMNRqsVxb zE;{6h^*9z0z5xCN>a)Ti9LH&s9C1+iJcM=rd5x(~dWM;sLXo1)KtT#R$N|1wPb%cuII&7Z|Q~w3{PYK=#e->@BfkD__sY8x9DEu6Rt)ElFeWsB*_1Jq*_~Y=aa8BzV5}q8f)~}_GjMa?8{E#EoWA!J( zGhQ9_Wla85cyh#gtZt-^jC&jxXpI=@*c3+Y>Q$%ixGX1>-6ej5IBf~oU@VA^jNO#5n%fPI#)LwMRhAQ+yz{@+3*d&1Dq5F8YKHp0y3 zH{jnSnCZ?pa0pnB!%f1IBi7?E>stT5vjUhl$r0<{cfKe5I`|Pdiwk_n58U zU|?PLNy3vO)@4VuuKS=0(IH2y?}I|Xx_%Y_Gc9t&x_;PQ$+y72Q}8VKEF0^pjX*H{ zWVrMTiQINTOqI*vh*?%uF5n_yRkxb~AQRxILylPY@hQSHT~$}m83nAammdJ4uGd8_ zRyJ>UvC5~}mu386eWhRQ>ZrT{Q+J&3v@uyQZ5Ih2|?txF!#2etR6#N?eHo-rK z{|mwFyAi>2;H!3mxJ+}b@U;0Q!A!rv;Mpehb-z}4a>V+&(=PL~41SGZ=8gFve>Z$~ zGvb%vQ*@h80!|N+ao=b_oDZz(@L{sY=Q8?X}3W3Ro;b+4sn^4LmmTSbaTU3Ay zgR{6WgoNO%7l~x-5`A7Ht*^>1*Ob>l_d9jnr5*B`>9R0?`u-ZQYtC8=obHg3ePdwi z9)KfH8-Enca(p6qtcAV|N1gNia(^vxCkapeBEihpe8Ie5QEM29%XJLxQ2*D0(_xcu z+tU0n!7OX0VAjDEf>}4Yg3&#F{9g&it%A@0vL&7cf41Pc@XG~XAHX;xIE1)M1m6vx zZ#`jLUY}OMKY+hMFzf1d!MvWk1v3u^1Oxg$5X}6a6wLg8E|~4&v|z^VhdeP|$|%9@ z@J9>gbz#1#!+PWYPH6pR!AxtJV5W7KV5aqL!Axt7U_jr`1=Hq>1|Ea3wT&9MuY_Y- za>PO5cMDJbe+eD~9Dt)f z?ornPcyh#g{7e;|Z@^LaBZ$lUd$qR!Oq+$Y1D`TP^vMy^7O#5|oYom3I^>A8 z&gH_>rrM8!{gcp{B|O`{`fUX~_YHvByss>BDE$5&;M_lLpwM}QEPJW zboy*_M2*!oXupbv@;IpU!3%?MlVI6!uY4msjrJ6YVX3D0q83BtM__6bjpSl7e5 z!t>2de-g|$I(;ITW74MvX0>XY0i0v~kR#SMTd1=f2MGT^j5;lXgTmj1u=PtEAR*Bq zM;sJ>6~g)&T_QTPOKYstY`!*PI|QQkf-ugc5JLRbb}c7}D?M*^o`LPqW>fT_zhB6-><63p^mBbaG^ zO>hhRTLd#-3j|Y#RZKfA@N)&<0l&b&s=U%3iiIaftm{PGSHey?I9?-NKXZU-pB%BS zpGx6d;MW>B1gz_Sq44C0bz00HZPK2qw;t|CQmHcn2M8|}F?C51vuOxsn0Z-cMe z26W~Et7|0vOSKd5|D z93ZMbUv}|eczVsO+L-9`T6XJG!Y7iy-Hog2%Is6DNXU(F>1=3_7C2(+epfJUJR+EF z?1zGx=8pxRw&Zy&iTi8e8F!ap=6A1P#{F0@%k*;dp0TZ#CdQ!tv?A*j##I4TKIJ2IZ?_>tk#*ZQw=;wc;Z6n z>$UU+!jmJ`YiaIvGY{0~y_Uv&27{ROf3<;&Xmc435VgMz9dc@aTliYh=XJZ;z-s*| zHkS#{_OeOvFX8_}@E_na%slLeKMiT@sWG{8}Z9C1+iMZ&Luze+I2UDmC|%s^JdF)lgcAovXU zbkX0MW&(Z^St;q)gr?as@i1nIWU9Z;_?LMCj9degY zNB9u1wHpVB%3FtvRaySa#i~x0xLDPp-^D1B&l=_8MB=l}O^aQfQh4cX{E!`R#LN$~ zLQEU`1k?6gf|=$Af|-|p31%KM(Z3jXDttO(mg9$lUxdF^a65edencJKqwyY+m^OU~ z6Ndo%3(lY~cn5UVeH?UXa~1Tc&vr{kydJ)~?t+IQtnZuHcBw;-SYM-;gztpkZeTVw z>K}pshJho%ddz%Bcyh#gY)5nPS&Rhv7>;(x5eJ1oEqpf0k^n~?;%xBN9vmS3H7__Q zyxLoUKI{7;(IFlKJ&TJ12!F4oO>)FR;l~^Lxj3iqcP0r>j##h9CQyfs0>bqKZIUAn z3O`Ty+u-Nnob@IS5H(*wKTmK__(FuO{Ww5wm$>AJgTntnc($3J3+5XzpA-CJ_-qHv z&wBVph;OmMLfBTwlOqla|GMyR!Jme6*6*l|>nl7t;-K(q-hmyq&BLNYtmYlzi*Z_) z_e0SkN36?x!iYPI`fuX^`G@f2h=aoOZGX%^+rN!-mW%_5#L|}&h-FLw?D~D}o51PW zZoh67%=14p@OA^Mb_jji?!){5GtDf)fbM>*=oBMNom=6jz*z@zfRwsqSpM-Ax9h(J_A_)&axVqcE}Oy-&uYl{5JR@IIaJj@Z^ZK zKDR|^XCHiy3tC_GeemRnwSI&;Kf(c``aX2XslG4#y9m=J>oOBq&v%~+PmWm6cUbgB3O^4180tTd17x)D<`bih%E9C1*1bsfd#e$gREtkY80PSQFiI^>9T zTK_Hlg_b;DhqQ<%fY;AvtGOFIIbxlMbD+n(vCeG+=P~XdaDem|K2LB^_@Tn{T8%W~ zUT)y=f}7wMBEHU#ns<;cIW_M{olG<078|&TaV6cE!jmJ``I$zYKjHwX5*>2HLE(!L z)_G_a9dg9FP7Vzjptk*V7n|8**?@d{TQXd&-{v(3nxxb}?|4(4{ zBkIszn}L5Jcn5seBXwScugdi;00`IUROkO9!^z z#Q~!FDeRL|{Zx349eSL68kl(?N389zY~%~!v-~|>>tyPT!2vQ5j+nZvUt*3!w+g-u zK2^!HuT2q59oC(-83)L0IO>oi*1wymIsxAdZh`0^=-%V7!9ddCtSc0B+k;?L=YE%0 zX$h~&b-T;+sP{!{fz!vj{35~B{efWGP<0EP-vGA>Pn~wbye>RPJ52vm!OY|52Cv2h z=&=4X;Pev6AC_-gnSg0Dp%Wm{odkHT*fyca%;N1mAHG=9RsAz;0R=hBKg z04ge$<&SGXE>bG_1kRuKX&vRBjkM5h$ z)30asaCsuXN zjs*$9>Aa~nBRun_?|IXSm*N0nThwb~)fYGrLYN0j;xcW$$IElpH+YnGHQvP=;H3jo zmvcHXZ9FUZAC~*IH1bSmoA6A(LokP+KMCemoUjVb7rwPw|vHj_BX%#T_$r0;u>0aTt zz|V%WzKsLq`*74JN38!poo!M7-|ITjAxEtL?-iH4>;GQW8Xk7Y5$peZRr3pY=JWS( zOpE1U{SvpnhPbjT6w zK3*z3*AYe3UxowZ7U9Ve>vYxLDe}Au+%%lic~~v_sDBi403i#iYE z0NE-!b#EwVX2IbuC_ zRZ-_193WFfha7RYb@&pHusw_(&QU^ey6=RJ<*A2DzyuO3Soc%*ZEHCWkUzswha9n<({q9K|C6eI3LSF9`d$W9*ZQ3ECGC(S*6Z{B z!so%yqrUXti!~39SofVm>U@X;MBR_TAUWco@I?q)A5jDQ@M4D?aZvba2~h37d7aVUv!RzN|w|0cM2F!{bN4iTT@;s~+qMX2@}ba}QX%XV=dak7hxh*Mmw zu2HIsRoxD7aTz>|ixdd+Y7JD-{U6>zE?z>OnS!*ySr-twbETEx;``xQ7rJ;Y@x?A~ zBM#vJc^b}g6jbX9YnY2)Ab*LA+lfcGcqj2l7w;jy%*6+YGhKXyILpPyiMe=#oPe{k z6;$u;u()8Opzf`x3loWPA4EwZX6J-NPQDd6WxX8e&?;s6I8JyOsBbN5F#K3nM_eu$1c*TA&~ZZ>d>fm;o{mRS1H z1_M89V9rNcXQzSp8~6yZ^udn}{F#Bd{?s~r{!hObhsZE z8x73o?X>zHQ*a1|DYMYy(d) zaFKy$8Mw^Abp~EyU_QsI^Kid`*BSU}18*TtaqFtxz#RrYVBq%*e8Rw|4V;KRp>6UV za+Zv}Ap>U`IM=|1#4%V-;Tuz`meINQJz3|vGkbMY(#ml?Ruz)Of_zP`)A_ZxVffuAPk zqy*Vw;C2Id82EsJ-!t$D1D`f9-`%d)34C9g#vub|8aUU$g$6D*@LU7e8o1fOEe38S z&Tz}P*1#JK{H%fbes`_E)4=-;e1urmIUgJNGXp0i#&uE*oMGUIfyWp)k66}D(+oVv zz*PorH1IM5uQKo&1GgD?qk&&A@GA!1W8gyuK5pPs#38qy`57XOZ37QB@Gt{s8+Zb- zFzP`Ap;*b z@F@dx^F_zC4LsPu!wj5l;0eSdrTrUtmVwI*TxZ}V2ENO{_ZxVffuA<;76Z2%xWm8) z4E&yfPZ;>LffJMBWl1-1$iSHf&NXnMfr|}1m-te*ergTeY~U6Hw;Fh@fj1cVSp#n) zzRb11)4=-;e8j*X8~8H=Ct$s-?W7nu!@v;(k0H)<)6FyRGy~5uaFu}@4ZO_2s|>ux zz-LffI2*q3eO~zS1~EobA?Urh#(}Txj58 z1J5;Zt$~{j++yHXV%hgtYv2tAe%8R-47}68`we`=z#kj8Ez!3wF zF>s!Nrx|#TfvXJMNGy9e%M85Az-tWLX5ftme!;-67k_+ z2OD^pfwK)f!N5fZo<%JCQDp|MGw>1v-(}$Y4ZP04PaAj(vFvfR8@R*32Mqk4flnCt zw1E?G|El-O_--eSLk7+?aIS$1iDhrC*uZlQTx;NF1GgBs)xc{FyurZF8hD$5cN%!V zfsYvYV*`I?;Dq#e{!tesh!S*J@OU zuP`;0*Nx&Q7%I#8p_S4_&GYMgqx1>y_nW#-sIM>K^9$;eHF14qNWO^D(Ab^FhZ;N| zM(VQ0Xcg7`azxjsXu8hT&+Gbl55I50?}_lEN?qp}*Zpt~zPHkil@C#I)VtOXqvukb^~*cm66M!`x_x`6+u2Hd zlB3D^#7?)9@o(*PqiNAwciq3f(@njqp_G@h0pG*v#_MX*U&85j67`5LQc1khO0-7Z z#CZKAHE$;3pUdg4-Sv?i_1&Daoa2W=s`UqSy6NcFQre7G@5xF0t2W(p80X!u-E=d^ zM&f=7RtV_3Z#^+hi6=Y7X3_f$x?Taj3W=!>NpJwUO z;6+kdR^MppM#n$aGO8KhK=O^k2gb^Mqxi9*QTW8VVWAKH_9`>aE!_sm1D;A zXqcxwgOHeHUUge+XzamacLmcR&-5@%8HT%$QfD#VT?q-eW$k$+>%m6Pir$RsX53}p zEEh+Jg$sMIeWp_P_-b4{TRa&wyI)p4Y#O!14xujr#>TUl^JsO;2hZuD_1{F-D&D&3 zKK^?0+wGHQ-Zsk56!!G>GkpnyTmOh4VVbkEfjQ1`R(sis?wd4m(R3;tFQ=%}ENmJ=>fX&x0AE`>f{83@5dJmlt=^ zGh%hkd1r~$b-wEgmX_8mT2NV9I&AE?vDs&`S7v8lc_uq{+_*74vC+})EIW!BQy)=t zKYz$cchs3*N>p@DpG#CH%3{{F{$K9A2u^g@sCX6lVzVK4RO_EK+YFZK97x8CIM=e^YXO)vG1_EN78 zpS$QqJ%@X#H?Eg@vwNvm-%Gu_d#Sg+mwJ3ZU2p2;&0gw#)Jwe!_$){-uE&I4>dow> z-p&7m9`i(L6g?D2iFZEIdbdFjKW+1orhluap1FaBIqrT{;?RQ`C0_?1&U1slHYnW% z{1_a6V&OUbgy#D`0P_%qqudK8j~u8l&(XaodOF>W;2M;Md!Rka^8mzo3_yn6=>E?J z)6ItCIi~v-0PSjf83?o?tc7}%Jpjac3_wo69-sH4J?5F`Xzv36+SBFW^L4r|L925- zZ}a&X_&VKo1TOYd!xh@2oC7^G-OuLYe=A^+>0SY+)4jxF?+A2CXh1~U3w!LXDRcin zk@mP9uI&|wJzb6{PB1+!%sbtDPr7_Yt6VF=*Xi>4CE`3eXG7@(Fw^C>H_x&DR(R6g zg%ekU*P_$?nI~O7b9Dnxis*Eo_N03n>GBypraKW%r~8J-9-lM1OB)kC24DBsORSEU z<4dB)avT$Ty8igg5c`!DU5iFG^p41n)A)uPLh0G>EcPJD)R`HULNQ2@ttOxF>6 zI^6+yK0_Wq!`XQI%NIR(N+QsEOE5j1E}zdb)9tv~{U0QzJ6ZIY?pHkae0Vm(yl&cF ziO1fWx_JAezAi_t*wf{>8umbSiLO8OtQS~)j?a$pe<`%+bno$`Yu95ukaqB8DC=~8 z;z@T93U`e*24AQ9hUn>ZtDtwGKdz|LechAp0o+Bft+M{Orq}6ydO% z{FBGt@kQ?cP0-$TaN6EE=X7sZPoKq}A9{?F2S*upTio6Zgtfh49(x_IXVwe#C>ML| zmBAh^u`2IO_}bppVozV+LHHe+{YQ(g=SEMubD;M(tps1Edy6OC4y4QHjae_VMGu$A zcaJCC=_$A#;I-&p+{B=&Uu-GJX?aY?#Fm!l7#Qv<8pX)W}A-=!5V2L~tSAy3Xdi*)%+ zI?M4jIG$rUhIs51rn&#?jZ;c=IR<*{o%*`_?pWF@gVXj#i#=VAAHg1`xGvG8^Q zyF{1cq{rU2mG1v?vK+U->2jQl`GR$%uUkEyt9`A@T6~<$6g}Pk#+;A$rTOEEI^7Y_ zBhHgkbH0uC2ZHG?fYa$t_Sh>Nf_I2W9D3Sbp2yz0d))umq`gMbW4%;*>}`QPmQ#zi z_cf2b_h4@wlxVLBPUr7#kG)Wa`yN5BJwC6=IC*lSr8R!tn!#y%PkHPeg1svw4n3W} z$2|6qe>YxU4250xwuwD`-BPj09%_F(TikG-{P@juxp z2g|$Mu-D+R*MY?Wx=5Gk{N3!a_sT=@c6z5_?^|L|w}Y9(-1m8CgRDxrr#8qR}ki+Ft{p;;sF|B@)L7M^e@&!Csq zrR81&27f1d$hwmMgr2rRLgSC1hpDUUUc3D)dVafidP91tH>#I<`90`iDDM(|-PCi> zV6){6%c1)yDVCS+CfGZNgh(g!a&-W{u9pVrY0T4?W}z(_goZamk9o+W5@gI1KK0%J zwio`7xNa}YJoauLg?69L7_Ml0i#_(zpK|qRuMJMyqrPrafWAEiIG|xY4sS6W^{`a- zVOr?Awt&7pGvIi^MRdAY-geVl@+ z5WoNL`@S>3-|Ttjop;{3&%85h*4h&TfzqvntL$FZxe%8z36eAnjQUOIN?nT+05D^{#13)_*%vJE#jHLYG%SF^TdLY>HN z{3lV;IBC!zr?b7QCjW5F#iwd=jhahN)Z`sBET1;-`Ble{`94k=QaidL+;VwApr@rI zW9mu$4VI+rq;*&yQEEqrZcEcz9}5&`HRKE_d;WU`spt(QKK(eEz+xF`BP_%mF=1S1 z_b&Y?$+M{(H53<)^p_92I;g)wnt6-;+;FQipua4ASypFgo3710UOvp~%+jAHz3jM| z)7Uxp`KkK#8CH$n+?mxeJ)r-NLDsXMKKW#<$I2dmMaW41)A3)%+IB?SSC(h$PciuL z!RhletJ}Y1&am3sdyZx69i;x@&*L)QHu9_e(e`%Jr$0$rNv8f^bQ_BEgFlHyej2mZ z76l)U*=xsGYYS(mXy_9^julP62!-y>Y8aUke25&OPV0-B5xm4Sx`O$KgBPC&=A8=W z=5#K1`vIc$F*%(*VF#TQrn#O)z z(@zn$o=RJv(;0B(ivHP_V_6jr0e&-2)cZG0AG%qIFHRTKJKcDZSPcErenGcpNRsI5 zhShb2%Od?vef*!Xq?h65#gJ+nw@3G#tEgz%Td12UW}dz8L(>QsZe3snDlDgqlh@(2 z+V$wZvx3>M+BJLM2jOswnYXte5Wk8n?9@Sy}-n+vN*0h%V=}C9r>1V zhsS@r$A4GCZ`O+%xx1fiO)Oi9Cc1>#)xYW2lLOJ%KXFms9yD3 zrZF}*9ld01ZVFq_wqicy!gmw~gz4&%YV_QI(N8 zP79TomtYpOex{##L9ZP))Eqj#C~)uAy8`>1&>$S;K}#Yld8IRoA5Ie_(Z4$Ixx=GBI8tE!@1*4rXu4URu)}%$mD?s(yI` z#;q9fh-h_9=deEZe#Vmj9$NWyta|rkF^cuyQqZ`JkBudET53efYz}6dhM6C(-MLAJ zxK-KZnIl#^!(IPxk#zT`DX%2GHDqk6Joy+Wirurzhv~myD5BT4x6dE;rLpFW>fQ5d zk>STl-&pyvVLk2Sq_M^dW`B@j2eYhoW9J)Rx2!xQ z){vgPYi2+(W3l@+=$hE()0&rY^?~ipjT93sO;)0H?8&#{T+(k+?^e5@2IE> zn7)z>{clc62ZFC;C(;UpTN+A-20xBjR&YObhlUwx!4KiFwxwtdi_$ReEUN&0%QPD5 zQiAWoS2*a-kNSD0=E%Y~Dv$YwuKyr{q$)a2FX%yn#V31XZU26FU9jtV%^a3G75^9a zHu~Aa=8VgWoqSsBf=eD4(i%&JqSr7ZaPrky+uFnHtkid7;5`A}z2H2-5?Sl4ZKq=m ziwaNvQScO`zDb@V;CV{OJK}H^r2Y-`hPtwo&kMf7)E@FZ2fo9C?~ub+n0g#^t*cs_ zZ`ItFu?9Q_HMyCfmVux$TAoH^?(kg!)v)ldEyL+r|L+_-F$S-16 z-I#pibV7z$>C)Dh3_DQs%EH$x-^a8iR}`c*fDscR8b8p|U|XI4h*{?9?o(EAurHTdq`%2LnTEC6+V&}}p*qm{7x1hlPXTz2 z$D$7yPEC@hU|Y7u$KmE+HFjkI25aP$e5Y~{X(XX zwK!yia-^4QGyDl%MikEdaobkRgs8QUmEWv=#&Y_C>=B%KUDZY_$0ooygNf>6ri#_s zO@(P#Z98l$IMQEH8nA1FW;_E3vkW(Ptg9Iq5i)b8A2}%Tvww*?R+S3ynmJhXZQsT- z1-fad`Vzu~LRXncUuZb=OX-jdeM{~~*vg4=h&Ed#IfX7_=7kLCN7PYj6>ZWRR@W!2 z66LA?l3jlT(nVjLGh@cIK&Y;H-G&Xg9J#vWvvUF~HZ+ykVLRMhS~78J$;$dklkACg zk#T{t2@@xT#hFI{ZNWXwQgQ2V**xC*TfAu2vdZY9&s8nHX4bN*dDqOUuB=*A9=@nD zIPohopI?_!ZPk{ur%Z+=9wVn z;22wsG19-|(n!Z~jEG12uV6#2|F3XqNGF~HOMae(U+v;A12awXYy{?64|#a*kK-1B z`TZ+A!V#F?%%mZ|G_oBzHgzOUcOoq1&V{8RKd~&!=ShSiT^cDz?GKzLD2LBs=`wGF z?HkMo$Vt{=0b7RamVx+cbprK7~4BxE+pp?a52y9Uo;ou|DOjyRb z1(x;6xc9))uw2CJU`h93PUEyjx*uQ`T*jRTyc{lhegZ7#!#%*4yY$}!(_E;og5aUd z^Q|N5yvMOb{t{T4Wb#SVLr$1n*TxF&Jc?C8e$Km0gK`3}G^7V$CA}D!hIC???i66kW8A5*G|BQ%2)Z6}?w7DF80T}O z!IFOgEc*}TG{B~~nB|f@tARO(lLuFGgbc=Qg=HB?zYCUzbYjWR=Qm7~^mbU8)?Q#q ze*#$Y?^oyt6#hQ}vtLopaacJIzY8q$c^X*CzlcN_@)M7T%Y04*mTUJcg$F^x$hDQ@ zM-MsUs0f&OjlxnMWdD>hW`8mF5$U`i79&u^pVg1mM zhgkN*mw{z_{SjF9jn{x_$S;j7mkEL%a{5;Qm}Mx2&4OiG(_v|n#Z~(=^)|-kJW7*{ zUrmc?kiU$~Fytqe`qCm`HV5g~z>=5wSpqA|RRc_uEG^RXkP{~L4fX{oXE-CmTqv$w z7lPoGaSKGu)iy=2@o4`HUu6KGpgkjL!4_SKjiFf7S!*T-G6V zCz=bD>yzqcgW+f2X5XMI=fF=hGcXs*59bP&LH2hGn7Rqgh2nCKVqEq^wjJXRwjL;( zaoL767fNd|{Xy+NgVC>4e%2lH!?u-k&iTf^8kggjaR<9!7%V?!G98)=)z2p_?G9v~@$dBbzvc1Y>+yfbG415@&DT6@9_A$JpQLV{@-}~ z)WQ?SCp0tF&zU!2eCW}t@x^Clhw2k6MuNi^zqu&Gha>`le0^qf`nk#{jE^t)D8?r= z#00??Uo{#us0i9GWkFawh%M0ush2b|0!gH{k*DiB&Q|^7VNOis797 z6UG)wEeiA4Ba;24ixynfY2nV>ozWDB6hVzsoVSHi-q58QiP8gpSNO*vJTF~RS zJbtMmJ7k~uH=P8FFTR_X;oMOrj87Yz@BsOQ2Av@J`rHy{`1nMi;J@7C=WZimeDTu( zhvw5JBm#ka;vdKoBwzdnq~wnz0tLVA@t1o16FvS(9{*&Ie~QP?ol(O0;yZkY<`Zu% zs^Onbcz}HIU7X}E_k>^R@n7ZfS9tuD9)Hy1pW*R8?eQP*_@D9kf7fS*p{_~2m%1I@ z9Oy4-Q@Z?Q|D;QwC}n8knq=NzjFO0!e6KLxc*Coe}(4562kPH^jG4lrRra$@jodN z;Wuclef(>*Z@GR)-a73G_*rg_v>fPT$KaQS^fx{J58e2jNptW|q$7|R)5{S48?~tG zclzT^+NwVOP1-kIztf+-s{IuH3dFq^^_qi!YJCEJX_)>&kN=n(KZvj#?d#e{u78~H z->hAlB4az{Dukc?*Xi$DwV9r9{(l4Wx=h6XhPKHQemDHg0%xWiyv@OPnhSx0BEPq3 z&%n>~jNgjz+qM6JpYp=Oe}^XD3BFkPzo`XM0bIlKO@N>Li(zx{Hp@KtnO}zGXgjqV zT)$J_-_rPwEcrRJ=iuK#f98fe_3<6;dH9)Mr~iFVJJW~%``QSo5R~um->+S%s1!_d z9{h~Yl{ZJ*t?~a1=y&?-gW9cq{6EwlhM)1cvgF`j+FpiV8q)a=B;#}C&(VIO4ME}w z`9IZ)T|e`bgMUb`aQ#mHf2OT){Z4;&rS`1U+2Hfb$4tZLHg>ee)AH?3$&u6EP9W~I1&a+%;$ zJ5q9%zO~keMZe$E0T3a*{fGJue%X_ z*w|c9k{wj9H)RMa?$fxOVNTwHV=Yu*Vr7H{OcpDTT_`G;pU-*?`Z}=1g=$QMWiGQ8I0>BXGW?D+0~2xTSFphqT3v0Diim&QFA*j_3W@@V`8|<2Cb4RznETzOAzq%F zocX@4W!0CFb@GT>uh%>rBB-Hx-5Q3ks^6Fpe&gEa6)RV5fM7A)lV zG`?E-@fPiyl%2d<)U^7ttX#Hc)rPudeHKqA-3`lHHZ>({IyNgC-~z$y3^#5_v_m|{ z^{Y12G_Mi8+5J%DD)-ys%0#se^6@qC=4B3dqH1O41{Cj1K|;J(ed?3}Bc>DP9kT@l zG-I_%DjDB4ZCH&V7#|?<%wr;Ch26LgMH3&m6=F1YGNAZpaT8KmTQ_bHb1-y_0i=q~ zSch+i)_aBz#&BOE<{M``Cdpg8mBqKS6AVI6aJ!@PS?zdnm@q%oy{x4X3ufcG)k=ME zMqMLk^n|o{T!h!QoR1-%A53R!l%6D7fwk2f|2q7N_0Y^viSt)BYs;{<*WCa;fIAF4 zUuzSN&?))cBc~mZ8h|^s<_hWhP-i5j)F%9<-#MGC$ z2h+ce9~ka$^=}C%^i%yF2UE2CpG#6?KDPn$|I_xsWi;ZSzKW?EcnSo z!|!(yQ+ADusT0?`n0oh@T+A|Ua53)<@=hV+GQW5`P+*p0B`oQ;!R3BTzYjk!Uxp=} zG~#rZ&gv$eC+GoK$^Sid)@<}6>JQK;ojKd6Z>xVSrbeDdaOXt1KGKA^7$gOEb zE}b;ubeBFIe*OF8aL!klE@?b#Nq6aU-MDP`3WVuDzz@s2u-o>_uXppGl11csovU>7)_M`Zvk58$U4Ru#8I@ak@*-0+u{Xk36IiOCG>@xtP~H z>=S9|5c9l=MwVUhaFgnqK6GwIlhK(mNpEw2ki*HtHGSqEnJB{g(B%Vb(mAkTgd7$M zhI0-7Ye=5P_u+9L8E`+H2RssPp^L}CrRl@Z$;>r<=saLZM$eN}j~r&oHGSkTBgyDI zAb?@HWZCJLaaq*7;iPEdl%ANpXj)C@!~i4u66mB6r@M5~XMRo&=Z+fVk~S4K-K8^3 zrX}k3Qc@5On+H5f_!4;&JhH+OCi5)l?D($fLuchny4sGeaFG@;#j@G*T+Fh|bwrfq z6RaakC}%W&VD5$`z8~)EE@pmt=uP?oxKmwBI_DbFS)V*VBxd?QaxwFDEiCC=eXnyd z?__?}#kauS;^KSg!s@@o56r*9GA?Pv=`NkkEa%w6E)QwMa*pM^&$zcBEmo_XKi_rf zq!G*c^JAAz{s6F)FXn2V7?&jVf#%(fwp z!oA$Z%i&ISG3ga9UJjRO=>Lr$m^rYFOB!*yOJ_dyF8siJ0hT+LG| z^9mhem5X_2b%Bc+uTi1%=85FL$;GUjRu_~14j0$K-RWXDLJwqI^0&hhlmF)~CO?Oq zl)ul#=W}K|agE`?xYKp)-R{!~RYBYPeAsv)rP6-SI2h z7d-Lyb?Ho-agW1geB!&{HoKVhVZzFJ;1-uo8nK)Q7>9A6fctG1x5LeXm2t)V2_DkK z{ORU_aTxbBTn;BH z->qBHh-JAfm)-z+fc);` z^s8MUz)XiFKWW5r?O=S;o8T^XaU)#O4?!mu{mPY7>++CBEafmh<=g{zlZ)Hn{e8_eL%tNTXIbleHA>UiN5N}|E0^%Iuzp?JTC(uaOuRN zPrCevTsmpQGCypOWc@_U|7--90BjyGc}Kap7%uBt=98@CA&pqd2h?q2A7uj z8n|h&a!gS!>7)_&8B=cFgwE-11hU8v%yhXGAQEzN$7?Ezb zgLB~IfleB6x=UxM%n!rzN=R|z4wPpusxTtY!0|i-C(SeH7tAv!3>cB;=Nv5Z40=4z zE}fzJ^A1lYoV>7uMf(D?4rnBgC|AUx^`o1^*j z&{^#)r~Wd2U^u2oCrykmmu|u@_w0;A9@2=@cjL!3GXD(Ao9GaSy7*$rbEgAD89B&c z1P?ItNF)DKQ}9f7X#MC^kX)l5b%3Z_4mcR%beB%QtScdtiX_Z1*gRm)do+D`ra82J zbWR4Y(N8!)l(#&A(_K0#ePmwg@CbUFgGGL*(7C41p0q+zJ#s1)y6#}nj)sFd#&w^A z*|&5i0uzAMQ;6I>(GUl-JL(hw!|K!7ATSlM`b9*}`HapE3$p-LXQ5%1!s;0UYRidP z@i2|BIx85a307yOU^c?)oJe3c!|EI~Fxz4ETmgknrn`-DAL(xAX(x6&$-~5#;0NXr zSbeyFV$IVzA;EOO>YpNV)-0Wq9LynDor4DE6m_I-7)wGahVhM31WAAbr8Gb=m4=hb`BA{n_ps9y~HfG?v9J;3ZARrYZSbk*d05o6}(Zww83# zPb(M~cjG+#pAb3U4p(rYg2M`)PVCOfa}~^clajt%!K;b0ocwQ8@GT0yOTql#7s>xH zu{+N{uHX&@cPsc61@k+=GHx%iyGEQ3jw#ae&xeM~W3(reJ=zUGgj-cGsHg z6wLpLk@OY?Zzguvqc#QKr{ISa{0OnTW<9B3-hq?!7Zuz??5=BXDfoQ_`!Rn=9{yK{ zT>C~UIHcf-3a%h_*T*Ua^Dd~Q*DJV5!L7vZdb(Y~_b9ks!F!0^HTMYxKc(P93O-8g zuFJ10__TugT8QK^iQTn(xPl8699A&@D@O9qC3e^PYZSa(!TgUM$+JboxPm(r+^yhOh~0hJs|xN_@L2_? zK~I!>w>$+06kM#}GGcdsH&ek26nve68;RXLV2gq`E4WR;_bK=xVt3E@h=QL~@BszC zsNf!AcaQm&g5OuLA7>1bCyUtKhmKTmNWl{oTtV#aRjU-dRKfKMZX$N~v#ko=uHbtV z+^*m~#P0t02?al;;6n;NO6=~DUsv#H1@q8K@|eWj)WQr`aG`?3#O_{ux`O8__!}^ve^(=U0_v+L$vG&p|2rtjc?WtKB{?^* zNqb*B>CdT76oV<1%0HN1r}6_2rZ2Hdl$TTDdG7O;N}SqfqTpy9#7r>=HnJpnA*Fw^ z1HFaPpOfYCygbsM$(io@yqnUWDd~$S{n;qX`$kHCt|YIf^k<@|zHg<(c|0$l)bxKn zWgymm@2SKYFOz+z|GO;%^P&6pdC8?e=b+wp=^ssI_`(UC?|qlJ++;7l!~^5KKuNUU8!-L3 z2Y3~xKO-x3pjTk}b2Ah2wU_>(lr?ZDWH9MMIpaC>yf`zVWyQu8Z9;ubON}-GZ|G_hnpdo@5!At`q)C|1r<5jP=WOjvuLG*3 zNn$ZZf5kMx=uu6Z*Rg!awJt{6FG~I3^EU>%qHPy zMGa1!9Uw9jOs>!l5JB|Sq$=$I5tzb2O6>)s^igXs#O+Z=24GLF+FqDhRcH=}oZpReKZk_#D6yMiJ^nG~moKC`K|RQ+|^qKA`%WgqK~w zs{kiqb0*5ZDsU3Emd2kQHa5mWAY&R>Icbp{~-CE9VFk! zgXEjQJ6Ncj3$^bT2FZ8pAo(5}B;TI~$#)U&Pz|CS<%8r~Gf2K443e*7kbG|qlJ8Tz zH#LaziaTM0;1hSj2EixpfDMB0g+b;|-2WPcyiDGe8U){@LGoQUNWO0jlJ94O;&wFMxqNn0lE#NIrg>a4_<|IY_==4wCOLgXGKNeW^k8gHI2VZ`C0A?j0oGzCrT+ zZIFDqydyP;@|F*huVs*YKNuum_aOP+7$n~%ybCpm@>UFzZ|xxY+6Kw@uY=@!ZjgK* z43cj&?@0}!UgivvZ~Y+ozIOpW=80yv%ZKGl7_Xiv`F;#ObOr4~e2*qc7gr$SM(Uk= zz(-u+hTMZYFvEcl!p?+c7_Jv-fAYvMsSUkccn+(QOGL<56gQstdzIfBX1AF z0?%6rix?{(ZadIjN>x6tKdyQSiX*^%w`D&!^WSA4%g z&0h!ZBNZYZ7h`J3#K$9EcrBU~DpzlcZPtB^-N%3BO8J9uzlH-dc~m zvx+>{kCgY2N8U)tb6-0UGNruxJ@WE!w@T*kT1DPV9(jBZ1J}6XM#?+nkyot9`zJ-7 zxbFwQY>$co3AlcLC&q6gM(|5s$p<6nV=Oc`H2fmP1}~T$+<7 zdY60TwLo4W=m%kIV3{teMBCw!*9Lj+^+<#!anw^S9U|kMGVTlefSlFAI17WPiRvktgmu!Y}h@BB5mRwtD1+6nSeDdE#!QB5x$* zC2Nl#d*oFp^42Nx{@^Ju-}jk~aA{aCG%tDNErq;|pdW-?4@*Awmy1w1wLLZ?zTEKZ<8YLcOH3s$0?Z}vEL(aI^@am`&C8WDUZBf z$dmsU3N}$Mbl>*KTMc>bSZmlGUvv3H`=YYc_C0`(olK8N0Uwfzx33vZwC~pyd8HnC zd~c@&;nGkB%><9UFyw_nXZ~)6B_H#5okt$u>lq8WG*aH@J@S@A9+o&EZ!26W?^chz zxsb>4Esd17#UpPQkJ@W2? zyh3oWeRnJJ(sTQ^2jBI{5R#l9DK8a##1(GXio6bwJPwXz^8U*suS${kpNhOcdgNt6p3D<7 zDY0>J-*)4>XUXdMV^6yENLSYLFO_sBc;tm4FIhhr2R`PZ0+wbwbCtluy2$ZJ>R{aTT?*&~nd$R(5aRgb(U6nPzrygeRy8zC=QyZzWB?~o#|OOf{i z_|o9_!P49cd0fY&k@!_NUCFl{e1>F#8^`!ofhzA`z{mAm8YwRee8e)0e70nQ%P`tY z!3R|?ZukyhS=^V%>*cOI8FU(a{N{%=5*C3^?FX;V$F~%b`Ga7523GciGLO8sP|3wv zQd%P2Qjff&3miVm`<)_>>Bs8`cz6JMCpzl0z-_Qhm*R)Q$~p$ro|vF%M@e*zECYxt|K2jD@V(KF#hr$G8PUgKx(|c6IeL zrjgMrCF5I0Qg&o%Zsem_na}o7&dbY7vl?bXofZyJC?o5Fhd>2BjoM)`XT0%}v zXYbGm($_zZb)d&aOe3c=%S|L0i&=+t%h(9NFPuo12=Sf?c77Ba8tFQ!+vdjL`>`_x zIr;~b5_vCX8rBTWs@iB8X^{iLgh=gkS6y*gw>!}-JR1{YMm}}WFnuK{LnBAB-_RWy z*R$60TQef3V{_Z4e|3po?NTx$-EniuVQ z&3=l6GaFWvO+V4zVejjha^)9nGaXe&@{G?~X4;lnS=Ou^%N*W3E8Cit8=C%$G2fXq z?qUmE<|u2HZW^_-wCJo$));19xPGT?j;@`Rx5g0gvct2CaCGYfvwXF)E{@L1XSKYN z{kpDHjZ(qASNXM5*l}x{72^LDL`9byLnF@wk7S>y(O9>o86`gb4YpVCM69zXX67C~ zs-G}4d;XnEt{iGdHT^FP)KBoYXF@1VDVdG>PLm|kBMJ1 zNB;wTkpr>S{*Hha@>N(_W?qFAfM=W!QC<+iow3TU7)Vxu=7d>wnto8oaeljr7ydF9 zP0_laGIMRz`RYb{{zmLLo$jXAtFH9h`9|>Lm~Cjmk7BzPabOi@1?sfO2Qm8vJvw7k z;I-VuxX?bKiM)%xe5lO#%F+N>B2#u5sRdf(ud%?P7Bh#VCUfInYpGN1XNptw9u~Lt&%I}}xM+*hKM6dI^->-QhA7WtTZ(>%vX3cc# zS>z8@`Dh@}a$xr>cfWq~`|EQ$!||yn5_9I7sfJTuY8`7H6a0{49F^|$y*KpW=~(`Q z{^$RJDdO-k-Oku}reJ#TRLrupE<@|7(>jU+dM`6&{p{mFaaKc4ivD)r^1Ml}X<73( z_OQkJjwI&AP}*G04%%JKOYk4DJr8!i7ekJmIc#si$V2FB?^3?|dy4oFlF7BJHaaPZ z5$pahMr<4Pr{jN%RkwdUHxvJvIVUB>_Ek3IrZKoDwm(P1 z>|Jg68!k4sWop6W7_xiqOArz=R@M%y{BtaVL7!?y^*^(ap%T*vemm;7CTO7?t4rT& zr8s>G^1RhN=rXc=YB}jw4Vpfuvxog-{WCR37QRvWK?Ft1e=wu-tyu8Qn0=HbKT~L= z+8Wx%v|cZ^W^8P`@|3T#?dxb4lxExIoWNRN5X)%T%0j6y?!p!p@0RXn^1K||W@&CI zi!Ez(+XM55l@F71RH)eM@;ifwFyIWIP_bDc7QYmTJZiVTYkyW-V_a_pqJe-N(8aI` zJ}s&=5Zo`Sba<$^@+q#EsPo7^RISzS*Pj-3TP*9AUCBsWf1u`-g|An>AIa$q#7C7{ zD+6OpGDq${W?(JnOv8ERfE}*WPWHy8>Se=F@Vy1;`E6`@%cyL~Nq5Kcw#g7_7l*B4 zduq0|I((wL)vQ075&283B-5Ga&5K8-&b~w|&j3M8IprBBqbB9&?H3V!6Yt~Wyu#pn{Q|!n8y<9U#wf@GO4Bf5gYuR7`y_aqsEX0GqaY@45a#qTW@WenPuM8G&2y54hdzBD79CQcDn2o z%Sin*7Ohmj7Rq!;zqgHTzmLuSFxJ0XM0H?7pD%Q-65pA^qCKUUy`gM$*PHd#?cYh& zHM%>$P^$lfbs#3$Z5Rx@`>4!ms9Qg*x6ht^BNh{he8Qic&Wa=l{OTKUFuQ7vf8^L3-{4b6QjXw446%EEE z#WTw@J~P3YE2{jMH-&d zpL~}8Iy2u|J>2qNZ>=6_`IlL!cmEfysupYXeCxW&R_0w+)eY7DQQ_~MnZ2Mit3uFb&(?bDwBtXE zEzPWb$!DeZo~bq(azegC)sWs+Ek&$Mn zHd^hmu{*CU*R6J4f0#@gGpz^fi)Wg?@nf57QuK!eZDHiTSgoE?t^1=oL^qBftKZLn zP^S5yU3;VqaT>>$7W>ipzbjJ8v>&{4+N3H!s_EJq{o8_8Gx9W&O}D2!j$MUSwY>Tz zUo_>Nc?CR^3pJMn)T(T{#TZ_+fK!?i`H;ub`V35WU)eZ=ghuXb2{C^Kg6uv-(k@BG0r08 ztmylB6woj_4eM^OI|g6yIY)r#c->LZw`D`{CBXv@{W+1IP#Zd9`!CXTXSdM>@jG4d z2gss}Uqm;J*ztJ0 zsPAsmcsj4JYsTG?x5cK#w+Y*Tg01t7a?@|`HAN!vNa?Gw?tK-D8{|H-K zD*nFZO$&2kxOmILqp`+G-CtfhX3yg4G2uNa-J@pvwWZ}FU+bPVr6>)P@|+)KG+ca9 z$Mo!u(vDuNa+ckGV4C%a@MG2c?Y^Gw?B9Y|uRqJIdUUXk!Y$igiy>#oZGP>0`%iFk zWxaX#64*gXJsr)KU#AB@pvq@M0r*F3Z^00!LZ~h~JA1}g>mOo;amPjg`sP{Y2Yb`^ z#NHH}l7h%TV$h4RE488Z7v!Ot+TOyMke#E6DzvY2H@YH;z9(CCkUmhFPRfJ-#ai)3 zC#LN1i`blTHP_t`Pc-^=DD=SH+rrhgdcK4*goo-=f(;9of!*H^@cA zU7O3Y#|680#&^G)wcwGMm7{g$Ka}JEPRPqHOzmYy;Mnbw?w=iP`I>B19aNu-Lb@qbmH$QD3?Fh8=M6<7+zh4|uHu}@8Re9J* zM4vi4wzPLd>uo7b9jCWkQMTm1_Zzc6&cJ-8-LRx2r8v*@-L`&JjlPF%SvD-{8~@W% z{a+nVV~tt=nbML}{l|`fjbZsNw`Pwujd4GU`ii5oi|6i}w?A5tHSgtULH4*a^Ioei z$Z0*Xpu%5WloeQCGL+NRKv0_$M018S&mQ|1wu>8n->tlh!tOZt} zwFPG?mSA4}kBS-o1y)wa%xoN^fM)F+VLoLoxy0UAW$mAdyxzj>goZ^n#i9?5*SFBO zeSKrii0!re7knmW2mPA^EmIy_yg6|C>Bo$1zllZG#SWDOq7Oy%jUr|w5N;{)O?gr; zG0TF1!0E9+*Gqh8N_We#KMnf2g`pSdZJAaQG9t^6&IJ8Sj9W4cI`z|~f1dqj%(LdG zVoDZ75v`C518DsyO<0M-Hc(xad#lF6J5NCYQqj8kf z+Y;=J4Sf`Y(Aj+i{}#)CAsZWF05dOy(^JdP(yhS6o#@U-7j?eI6AjD6LDEH*S((3V zi0IB-1dqm2r(#9SF;XYvV9L>%j~|Uia9oEYxy;tTV!I18E;IN_Y_1MeWymQUw*|D~E(UsFeE$M?k|PdN!l@lkAJ_OmMle=XC2mX=7z zEbQx@DZP=$W6(68VANAc@IMI z50>DMV_bc4UU(1J${AQI<<8oe&ErO#*EwfkavwBo0DTGVm^d0dXt3$d#9p`B)&FzZMwv~R(FvcVHR1rMfRwMoXK`^ zR-hnYtPcBUKj%W8OU>UXH)9scBtv zOMtHq2k`!9%euOCs{^>GrGwiM5dX8P%Ncd`RV!Skz_bJFz!ze!cj}-5;zU`sldq z!|htQx8?VvGpz}u?RMSj`Y7x+S8r=w-|Woj-KKCqQ{D}>xQeMZRgNy)<$u%@(kN*zm7RL8=CA8%$vLHGHfn1 zt1cQY2ey2U6^DmwyBc!*soXO+ zSbo#qW@rs|irFkGDlrZ?8qV-s-!#I7Tak-yd!7$G5G0gJb$mh8fX3C2_&^96a(5Nm zWwPd|nNQoj7%I)k=v%S;IVO~2p8lDBWc~TS#ln-a(o4vD zuF|YIxw&>|ba?hw9D3FICbz!3yfj=#^w+Jl2+v320aA{S3ny5=`JEslXH_6|LA@6dXxVa$K_J;m;;GomhzWMj{M7Ejx3 zECE4ko<1GN3HtkNUu(W|dZ3(74_L3~3lL{ELmxe6JhPhzHmLIax3laFU;fstXof$( zFzf14^URbV8L3xl*t3;oG#b`}XU7+9G^X5}Ya9MKJ2U25b_sTs+LU{Y{S!5WcBN|L z8?fs(pDNE-UKG&9)1k;8Vrz^Oc;=G1X=K#A#G0LgF*KIDnAGAZ4sx6a7Gj4MJQRx@ zjBV7T8NTKy9vO)p?mKfzhgcc@tF5sGL8p@WP$S>;RZQNBCnCnkW=HFDezCwHwrw;f zVok)z;iH91BL5k)3Jj>M4b|!TldMbUS3W#RcZQZTuzJ~G-Z8}b^y>0ZQ}z_2q3kNn zHgvlRO0r>BVfw(X92vo0+#j+`-?(C`Fz(Y)jtlQz!`oIO9qt$3b2?5-rTKs9EcpY#PgJQSh7zScXT~yKX`Upc}G{UYeov|%rr-pm=z_c z`r@c_%H#ZEnmioUO3c2!GTFXD|brLH~63MDJp{l zN|EPvMSp+eW*+H&u>Nh|*Zjv)IBhN(a;DJV_6?-WNe7oKmQ=^ujzu#xyZzXdd)~A& z^u498_CA~am9vr8VyB)f?uli8_-@&-{N~gp`_5MWC06~T&zLjJEza^gZrB}0e)UJq z8G7Z>*yT^3h-%e8T4c^BF>lkIbBgWy(qZFfQS6OEJ%w zc)}+hjE07FRqM0Gou2#|XF|Cr55(FIM}M@ed>Dqz?-*sH{*~@vSFEeMn0wu>kQx0^ zZTT?wjMo@v;w1bBxshMQ4r61PfqpV1@&vTU=!|{~18Pk?e{cI%<;T#Bs_Q4)^;0r> z)w%l<>Q8MiqAuIEvPq3`KFknY3{-i2b^W%dFow=Vhn!#6mwnHj7qLvWZPhPU+|oDoKJZq zeIY+{S9vZr*FTSnD=XTGj4KG?)282Qe+PZ~>Lt}F+K8D8tZ>DG(^DqBBNJ1Kh<*Ri zlicg`WcUuF3Db9GN#>6BhxS{z31DZBFFmvK-h^`xwDj`fyCtlj=EEE~VrLZ1JAU*-1fjlo782grB~RFWDw9DBlNr~hCIwx>s8 zO+3FW$?S82sT4|q828R&oD(%^r)q`-dRm;;#zW~7(Yx?eI-0S`99C=Gk83Fxmkg^I z!=)+Hti3jSm9GDt{i{*$Da!tmeW)NiY;}l74EFBJr&$=?h`KZz4{9ow?VL7!!K{FJ z!kGu0-(;(YlCl4fq0-LB44msgfp)6>_#a}Oe~g7Pq2!*5-VZ(3ycmn?BrL9W`wyns z=3!@v?ztlSL+g;89VlQOjME$SrI}XyL*t9ak15Y6_FtPlF5)cDje7OL09yRo;Izp- z%d)3dUc2yUv@v^Wr5!Y)?G+1(HapLr@(=rQk3l@?Yh1WA`@`9XCT3TZcJQIqB&#kI ziWK8HgZ@jlKq#}ZvMgBT|B~fw0hi*qDSiByrI~pA&>q7f@XwugBDIK`dNwunrPD{8me8Ljj2%r>C^NYdk_&iGn!j=o!xbL^7KM2zLL1L1Ir z)jmf5o(zjeDY>k;HXKQD&hs0Qt=o&rGjQs%lbnq;M{~-8*8VF{dgn;LHkkTkGxIV8 zU2cfzav>f4Xqr83a!JayHJjG!+uSsk)@)o~7Oc2&>--^jcrVUv8W)B#)!MSEGwSW# z{%KZqRNM0pigmUrrw*<_SH@0dsD2}*vDQ*pYi51#Re`{m&3cn82urvQb#lY}RI^sU zL6VJ%D?|la?d{`B(YYJk0J~kQxN2*7M!?Rf$J$pT`BN&EZM92=&rdN=>DRl&TJS=2 z$w*drmcCT-Qno#6@_fU5K);4WJEH}8-(0GP%OWrD)JzJSpMptD_J87klo= z{zF+}PMc}_9}?z6qL+zoLvzM>w=y^GNT6wX5+VtCt zai$@j_hXh2tHN}v`wHg?v}r_s8MCU^@p9Ci?67{Z9AL4qs&-5(x7zVsX4>@e#rl7U zc6ENmz86K^hV7UJ_iZ!nQLGI~E;D%>0{$9tXNjul(jsW0mG8xxQOABW4VP^Ac=(cv zTeohmXz6}&!JMs2ZqaIA)~i!1Z~E2{D5I^X@Kkx>Te0R@Qx^U$7G11W{w=2ejTu8= zLL+f>AL`Sl=PV>ib_5B}U5?=38xI-YsKoKZ2a%!cyJ}J~V;_GzmT#m%Ot^bj}5f&8ph7-g2FjAaJK>P??v1yt80iKi`e>Rr39@Xo))xwd(F(Au?!4qx& zxXglbVy1}eI^qUk;F_%q0xjKLI4|gK#zPOw=jVYzJ8o>qn0;O485FkJW=>Wl;OJh@ z<0e;$W)WBZ{|3~aj)oj z&q~xB@kzXR9-pOB|99Y=&PTdxa;8(Xq#lyicMo%bE4#b=Cxty^ykZpP)a%-brXhF07D@tkdGn_tVV z-fg6=(kijT_G{gbM>7I#_0f{i-Ffz!(U$Rpak`b!a#JnO3oOjk^II_Od^nbC_@;#bAB*SV?$dZPxAG^kz@(k_%sZ`&`d!U< z^!^;4tJnuu2rltxWogZl6GP@^V!5$i^fepTO}V$J*|;9-%#?dqHXF;ZE=;-ii_LlS zvBpffcd>1Ju{om!i_7Ml^eOkwZZ?)f0hn@cd9zVtXMAnSy%Vv@Z!v1aO({3s7qW~x zEap>oTxR+2-yXR&XV~0eSvGDd)#(4ifwZ({dnKwPwMg5ZZMCccevHaPv~f#Kslnrf7RxZF>wyf$082 zv~u(6n?`i6+%YT~G&qFC(!34#rMBZ-zU5Z?k7Mt%I+t^x-@3yu2Ikx#1}p~mO6Ez7 zP>fcQGcyH4EcJw@1?sfMOf*cYcE&PNZ_*;y#4KDI#Pfg_t-0h<)0aNh968??sM=cM zKl6G0ps%Bg3rO3@)YUl8X&hg~=3BLX)6KWl=$~aWrw#@h*KfRed(Dz)DlbwLL8XB% zq0eQY8}fkPe%TlG_0G8@cZuI`J$=p`x!2YY`XQL#$Efwa6V0fZ^X;Nq->GQEsyW{t zRqHz$&1jtS?YwC2SL{)frreXhU1$CB&7y;8d&g$=UJ=m4OySHH|F&76Mn=R!rEO8Y zm_&P&794@Q8bkGQ^lrn20xM&A_YPD|5eb;Liv5k5xX3s5aid})l(-g@&2Bit!i_Il zwO$`Zwwp6>bQev-W!uK}&>QUs>*pKOCXclBOBlK_v-ZI|zqGP^7z&J|Ep+J|LB4s7 z(foVtysSCT2G5=|heeG|<|XCBDyBev9$CG7a-g{;O;01MU2^Hho6l?=l3oz_`p)+* z8HyVsJmA6+qPW>{^V{d_XfM-u^qTpGd*P#Z(n~3>hF*|_KMeWS0qE+6^XtRe9_HePQ?{F;|aWj6STjQnVgNt z(%yp9Q_++AHRL&ZGJ^IqqVcN-Zl+F-+@T+laaNhPAl8(}Q=-vRn9J?xshfX!&aF$- zWIUl$R{N)PTvSFM7&WQ#XXotwyF!`H^%N054bSWC>aRdVZS_}zKRIV!hT3E`LDvKW z)yKVbH1Ygf&@Hd?BNz|Gd8XGt+2B7$4R$JF5PQgAIgkAc<0rY z{s>7$hv(<-@tcUvuAsc^fYO*Y88vk6oH}9s~XHYrZ#b zHhs%`TFiW8qG|HhBX>K;U)Sn*`=sJfOZUz**AH1xw{!WathTGnVK~KYd%%7+h7l5N zKQm?GTew}@Ge7(4(gVISGyj1hOCJ0fH#2awg%hu?O+jZLKhC@Z*CFyxeYEiRvC5Zu zl86JZ%uT`DvYksg+{NR_%Ph<3{!67e;C1$s+b-3#>LD7AeX67S2-_NBL}y@bG{C8c za^`0`&rm|r0rBuPX26NE3ylUqT@^hPsMOZWLZVC(==#c zmNhmtRl_l)WrgstK*QAx%NhrMXycYOUN#e_8PwaE>PyZPy(l45lg9hH68x&DcD#&(Q3Y z8at{je=WC!yP4KgGP5Yu$kW&iwVs+Xad_*AGqZBBs#Jc!%-S<+t7p~(cv3F8#dM1( z3&4ZttW%&!?~VF*rO&Kbxpi!5{*=kNC>NqyGwbY`^$QpkGa%e}g5sQSXykB>?$jur z!XVFG?b;bT7uBSTqdF)l`?g|1NmfwQT^M_%b51u{5q>QM*YWlJ6*~PJmAp^& zLF5k*uZR62L_txE=?tSj_hP z17i^T*GdXYGD1qYwc;kgKow(-d5VwBH4##PUO|8HgcJ+i&~ zgWlLTW11=6;ZjP$a`Ze?19kjNZ0LFvf^R(V5sohn`Oe=nq>N89&lEJ{`R41EY2Zoz z*xVI!i$`uP(VgAgF$2CW*7auFEg}7P)13~07Y|;IS=VQT{;kZyBTcgfmnEiJn5tV} z#Qad^n_69#1Nzh)({S2-+#OL9st)c3;W@N;D+}l4?pq1&hDXWuLg&ugOZw1At#2bD z`u7%HRr7wVF|{^TOK&(c*`Bjw$kH)$zLl|msJ3*{(ZxkM0Y10JMZH}sFq>4T+}!q8 z%pho@x7e-b8-c4Ln2r3-^__T1IFB3`u{s0eD)BhUUYIpb|6S1OS7t7H)=6ier(w0k z?>wGh@cIK&Y;H z-G&V<>(;F<`RtqkK6+kahwX54Y01Q?B`fPEO|mD}MaBinCQO_V)}YX80a(UfD!z}s zY#zUly?D{AWtGuIpQ~DY&8%fr^RAgyU0JoLJbY1QbY6MHoh2|hg^?~QQ5fmU4W@LL zyWvceW}@S0l7FP@m#z$->(Yx|SEg6y`sL`5^aU=x!gT|#E7O(yc`jZ0Wjc~?Ah*IJ zPx1v^`b^iA+t&V(#o{$V-fmVhH}Fu1lUTz|xRMnq+AeA&_a|MRE-bgy4_Bl`>}n zGn_IpSqYO&ChI^)Ch79aB8(%y+;Aa&mXZAOO9jdJS!a|_7Ym}`p9+@>KJylZrMXbt ze*+KG`W5VTu#9`Dn9`ERU5;?3OZPQc#)VER4AUYejdJD!XSjH=!UK{pvi{j0D3fj> zEaS6}OF8mO2g%C9vB9`>r?_!$a9#4Rfo+0ievZM?kWS2T!8FcSUbP+hRGs|zsE#nn z@-q@4%n#jKSn~fftgMIIfoU!j_cP#O+?8a8Nye|1op0`u|4Xh*{?)K@jNArHLpm|* z+JgNSEDh@+>@0o|z}6OLrbDW!1paP$n_wAIez`OB!(tEXC4)BP`>R&abyn z2I(EJCM@aQur#C-XTg$w6qacdpN6F&4{PQ|Mq5M%E`~=pjc|0GM*% z6^3ENTt}F0IV=t7#4^t;6AkIoNcrp!luuW-!Dp5H5VKz~-LC^Ph;lanAL`ydzOJI& z``)VwSl9tdh+4GbZU_*dEomAcV3D*GDNvw5k*bw6P0}WiH_ z+r!ZwMXjEy9IeNqs8y?{Dr(h&g@cMm)T($aTI}=t&bnsrE2}$YKldN^^Lgfz+4G&> zy5?Flvu4ejwf4^5f?G|m*2Xwi`PRGGC#{a>i(~&R6~}p_UmW{kt(Z`*o^8^pCuuxi zZW2=j`?ZS9U*z9yDf*p?^bh*KC=$@&sfy@dw-kN5BK?N`s3HL!j{W>=LtDTM zHJzh?4xg+P{WNjB=1w<8ZxY9TI8RKVYz*-j6(l5$xg6;m6{*{s6^~HF&)XFV<;v0) z%92ta%5vQyrEH5LpIVeBU;{#lWL4o5$KbDSKapX+3oH0E-oN`lYXN?)W%eJ)TW;6H|V zjC@~FhWad0jBS6NI3BNMVnR7T^QBV<(hf!Z{Hr1XdpP#(RzwAKm}5yj_bL+5;dm`L zQf-gtnqM2hC(4epv&FH`FA~Rbdx@B905(g-aoqNc^%wRvAYj~MGdw}xerxue*U|o+ z;%NU*;#ju_#Ib)qAtq3NIM#Wq(}RItV*mSbeu8vNPg9IOXNd{;jN$*!W!uz<@%X(44(x{@k1oMP}!-np)B(O0ed)}r<@0D#~cPEiq!1{ z?e|>c#o{>LRve-}9AkWvo})NH@jS&?pZQ`!x%xCnr!48PB4wFlV?X?}m{6{4opj2Q zo~cM##wv3HZ8_BV^nDoTs1sF&X0k8p^I}E(&?W*pJVg=x8bw06y7_iZl?`>f5Mu@G z;W$<=703N95dVWB{TN@S2^^fD~WuZ3Z>qA}X6JKXI zj`>#}qAc@2`y!2FX&Ra$^_Z^sPDRGm=M*_NVa_8$x&HCTnzGdGgBUB6vtKKnI*@Kq z#D0=0aJf?Ub)EQA#z$!*^9Z^=jvRhL2!4lcf0J94C}(i!aOhPZ|1^fIWu%1nl9diuH;&DiX^1X_Af~($^{ChcQJTQTEG34K~`8Dbr#muMVzbuY^wu$3hu~W?aOWDW7?=bGt zz&g@+zy=xnf?4xn|8a5j`Jgynk3K7oZQLd%P!_&ODP>=zK^4nR6f@4y&ttGDU=LrQ z6n&l3;hm;0R7b`2d?%fzK-n1L_@o+1V|u>C@er?9_^1B}FI1L3nV^UdLOJ`{(%Bd3 zOhxSb6=?$d;`|^`7RDF)I>mP5pDT_1vq#K22^*eG5hx4CdA5EvaLpdJ_D;rYO(83YOL@B@$j}Uz`_|oop%P4z(`z`;BuWJ_zOZ71o`q zGbwWy`|406U=Pn#ME_^SL=pV~#W=5iQXH>qUlYgc%j04~x&5Lgjp?>i#P~l$kxlGpD*UPqhF)Q_^DT1qDc6^ zD~fS^{->Bwu5R=N?IoSAh@W#53E0E&cyW%zewZg_oUpG&iUjOo=3e| zcVzPK%;evd$={yI-;v4RmC4_e$-gI)e_tm5{!IS9O#c2%{zIAk#!UXhnLKk?DO44o zwWeBCZc}Nas4DldO#Z=4{u7z}r!x6ZXY!xPw{ROJepe0?V0kjbB%$v0;5r)Kh}XY$iBd7gonLRD@?CVxgI&;3y; zRE2B0&rc|2L^__Ce03&&SSEjXCeJmx6!eb(Dy(yS z{^(LhR2AMIC`nae4dL^w%S)lE`1!_Es|xqmetTUhBhvWFWwv9wXJN!e>7G_J&eM zR8_psjP~58l|ohc9HP%RmNKHM;(c=}>zg7n+fUErr)Bc2A4@^wzmySG74HvHS-*Ob z**-IqXMI@;Rk>NEjHs&kEI5^`iq8vU{;Z7s*_nK6CLh<^vHZE2?K~$ag{tB`Y^qfi zKhGEQuPzyjs&eON@@<*?oJ@XhCeOOR6sp4K2z;J1z~-#)*T5mklv zGD}ib_-uvGUs}op`vsZ&Wtsftnfw)*{K8EB%1r*MO#bRjeo-cWO(y@^O#a$TesL!M zx=jA{nfx0v`6ZeB8#DRqGWqsQerYD(k;yO1pz~$S zf?<+2`5B!&Gcs2Rjzq2Qzc?ewGqP)S|HTpED)iEj?-_GPMS1Qh*q#sDug`s0DLQ^? zbwBn+r7@s?TM_#yipS>uc;GRm=&Vd?<^7N17|>ZUEmdS?Rjbd^@D5lEY=31Y|Ef$r z{x<++u{_#xycbWYDO#VnM890W_{IzsLnwa!$&Mf?lJT0J+sz_u$J+P^51@6O~`XY#jZ@^@$Qyh9NK{rmY${@a=S z&y?r*vvR1-t`KWbgk~sS7o-pHIu(DlmA#I|Jh7_hw@xSS((=A{l=eXw*NAd|7#|n&{-B} z|0Lx(KjB(EFPNr0S2<`=Dq5sHE?dOF2J9AIE2>>70Yx_c_)70;^ z`epRDC?5mc-<8SVlgV#ZzD;)Axzy_aF&h8_K;llkZf%QF=Nax8&Ajw!brzzdw`TqCD+mC0eV`c6>9l{R!onU%1lN>OJNE zQJ%We#@gH$a(Q=)Mg2}!zCr2DVf)tHg_-TIRi5#iUT^;+Hp#Eo! z*}fxperEfX%Cj%-3~KeOxyv%!M>6?am1lqSVXfXC^_nEa1&e;xnA{Auni7A6YZnbqolf-X^>c6}@4AJ26vPyOE+ z@_TaYlwT`8R`YPJKJT&7%1a96KB_$RN&P>SDswA$QD zlRK4Xyv+;wmnEMYlb@12raW!^XxM&2^1Sjfu)pJYu>hWu$)Be@{dt{Yt)9nSo!Q>4 zJaw5Kw$~@?l*fcS?^>;bK4A77qhs~_?32pFY5tD~wkl8g?Gm`&d`)>>npHN<=T@}y zI}Yswt44&qojHB^L8^>&kGA&?baamPuIg?d?d|Vw?;Gsw=qnklcp-z4?t!lMuI`SN zqdnQOsjBY^>Fw+o?bd$u<(UIn=lu9;cWHlJ-Ms_7)X8jPy|oKA#Fq4T53JPBw=VBp z5q_<;y_8o`ne}(~t7#>-W1SB5+}KXTmMv@VUe%u)>TjnXMtiIa2A8*E5ggG|Wcmg> zy4uwBdJ%gAthf5*rTxz2$#(JXWk$4=i&8rt4F z(#fGtbHxq}+r}JteHX@X$BORU6+``lT^IDMxOn7>fr|!v2Ue8&jegO_Q00-q<)iJZ zyGGkpZYb?`q>dpk=xFv14mgF1a414Oa8=52=u_j4VKXQ?L{T>t_c`1x>u80~&cXhE zb#1Xh9M4eGqLLPHS=E}{z~JiAXzCkW(cag+s=H4k3zmzLPy2!3Ah2=uaIeNHT`%9N z!N5Rw=V*Ipzbn$E&QJB+NN2}@hRi^xoR>xiB?r1!<3YX#N5WY*+^%vR!~MD5&M*{L z^)7csx<`AK4Qu>$c8rYert}13uy+pK=n8~$vVTQ?I1f7eheDMH==;9zj#ch#>r{TY zeYyO`)|47==d|is(sZopXWG!$tI8BRH}rmon^+M13CbapmKzxw*17FlH{89VYp}ng zcR&MsO?zig$3V$#7=GR@f~K0mgR9F9$82d=pRO9|ot0zD=-{Z%-Ec%WQ(RxU-Kz>= z_oahX+Q^3Xft5N!-QC@-P0cfBwwE>z4fgeR-sq~$kq>7Hd!$scqe2xzT{RF7v4PGg zUuw9!b8xt8B-h^4t;5mTF*G9EK26)XRSWftJr^=_UZ8=hNw?3WHNB%n#T8pV-0j8! zU8^7Z>DK^WIk9=iZk#)ZgrQY@fCyZBLlt5m(w-myVbcRg^B*^?$OISI_GqCY0etS`EKc4 z<_>A5%Z4@f-R4YnT{)e5Y}B#ub zPsuIDC3(fw8qimd4zKJS&CTr`xNuqf%Au|?7jWEgvJ7a}O9$klt1liH9bPcldBYgt zngNYjUC4UUt8e^{?O3*0FDej4j6>eOkUQ!{9YYBd%bmV{`xsA5NTX}o zhXz;cXmeS|egB|l%h93LW4q`eQ=A@bn$8@fYuo|iEYt+puJ0BfTIr@#_O(ijt3h4X zGpA`$9y4Sppevcar#!3>iY=ig<#g)Gamek9lBoq$&VtMG;Ba@2 zStG1DqEK9RM4?z61g_*o0pA+U!y_ZTwyMw&*Xf`$XIZyq**BF;sWKOz@>}DgF&w7S zg}u0=gSL;k*cZ1_AC=CH+&D7YZR4${yYq$-P1m7WszF${SjEF>IA+6$F0wQ!4$rY0 zBjitqElS9ge%aPHA_&^ zgOVb>%q2`aZBOqLMz!W_@7H2wQ0oE!hvvS0mXRA+b?&@CNv9eFq9tm|`X_x-?745~NA3Y2Xbq~aE@?YH}9$Kvx zeY!|38dD)#zOdX&*GbFzIy!F%>z+`(q5c~v7ry;4y-Z%MQggdIR8Xt^bc6>-Lo3^L zmcJ=CwCski<<0FQJsmUC7HA2fWt0}~D@Rzpck9d@Sh-xcV=IT1*Oh)1XL#7#%7OnE z#_ZKxrlsk^gM?Mw%Gglxmnll?)+JMNdGDI;uJ&Oj`}F8Um*Z~GZwQvN$Ay-Utlo#y zx1w(4bW^(E zD%qKh#>2?UZWi-4+S0D#J2S%&W8&*}cMBTL?O`Lcw%tq?_gC~j#)=ySeeY(eS|u~? z#98&Lx&5W>r7NELw136ua(zu_H$6`mk1Acpt!`Jhza|AQ*$YyzA6Xu5SZpnXhp4!E zWS%LM=5Jh#dE5~1=U4O%F4F=%tO&vp?ilJ#b1T|)0$#RaSToL$PCpI7_VC;z*``qgj zJJs3yV{qPdw#K@#?>b%-c#f3x2OQJSe2S<}&o4167%K_S;m|1;>Lcd475hqlt`~*S zM(Jp9-gLGldw5Nschw!9a%hW~eZ55y9sj}Slc~+grWbvhPQPGZqhm%r;PaKzr%}Je zc%jnEoX$AFhUavAsv+9<7!N4D!RaH$H!5A_^tT!FeEjWBzuWN#jK8GxpPl|m$6s*F z^T~Kz!ZETjPah@M>%~GmrfZe2)B8qjzu6d*;9ojE{@Zl=kk1leuSbWW?_kC$pT>jP z{{_bUXWyHYM~A0~lPC0|5c)wn8k{%%b}{z6r&|ywPw7SB9!2zmao+R><&$6NMdAI5 zp{#M<^hV{AU+P8S!;09T!FkiCiIZRHMPZX7HfV6(bk61EX}u_XP7xb4IBz;*GWoS$ z6t*g2g9hhKZxttWs=`+ku|b3Lrq329ztM}rc13K^;JoQ=;^Y~6 z-|9u-M~c{>!Fki?i<95!MPauhHfV6(^abMN_j*yF>#;$D^QJEpCwujxz7$(w$b7@hx~ zo2YGZ%vZzxdQmu9u}&M&>Wr0yPYA5&VRnEXXA3b!g^ zj|S&W|0mP$Q94O6*{2tU+ZC}#gY%}}Yx+h~#pF4?DBP!rJsO-heX=eTljrrK@Lfgh z(crx4jpF3*dQqSZHfV6(^l9SQ7EVQM(BRk>#z%5MFA6jd8#Fj?y0AD-s>O9jqS*1W zd7EQjZrsu@b@_BGO*d8&-djhf+#J(6*6bUd>*T8)b6jJeFEkwu&Rd@^F}<5qG4^@8 z>1c55^BYVbRT_@F_3eP^XmIRv>KEG>+RLC;2yN6xw9^&qFjQz#gvrh_rvGLbQ{UN+ zX-~o=q%c>JvS@JL^w2IFtMknU4IVRw_eoH=ToFIC1&-%Mqc}NAFA8D285fjK>?_4+ zS5lqUC-jdU>rjVX+NcofZ2i!peBIHhcA+sgml{(p)JHb-NtfyL+X~|!D(y37pJDAG zd-^S`J;d0AwTF18_&tj3m->FtxS;f3jA`E{W7<967(drK4&y|A*#BzN*C~Co@jI2? zVaz`7Gybg74?CVFPVC<y+LK_#Doq-m}3`?m$*j!4$~(p4Rf;e*=oY=rnAq`Khmko z$4%!re$p6ws*C@EG}gE<$Ll4=w3W|yqSFW0DZ-Rx*ulkXis|8aiEq{Rx0((0`iSwT zm4-gIe{Uy`A2c{``c~694vg)@{#E7?)6w9(>8;q%2!;Pt#3ve@H+{A^+WgdP(BNqE zThr;AHgRJAlEbu)Pc%4hdRXg9=RZ^U?;LF4d9sP)@D$V0;5ZIBe#y}i6slo6$H~XJ zF3eq%P}2Y0t`lS1sR++e@tchC$9aPO-%2+dGZgn5^B*#o881<~(DCbxdz7v*Uayof zm)Hk?Z#Eqb&YP}X7H#e{8#FlDFpi_2`^^Rojy8gy#W;S@F{iCsxbe@+Db^e>_ZQ?79`L^n%#>U^%*puw@uVf@&4U zxI-x+^sV%li|g2_!bytobfxDSw<%Tgf_|RTaQ@2%KEZUx4E-M468cRxXmD%`yGi)) zszT^PJJuY(c>jB?xbDU2F%4@)F~^;01s$L3jg{msl{@sF37Q9t@x9jgZA$;mnEhWa zJM1|(uUCZor41RcQaa-FFjtt(EvEB%&u}i=zqHE_SL3; zTj^S3e1z+rZ2n7pkLm2^!^T`=KW*8LS%!1*87 zRBtmK4UTK7u)dZ5JEalX*S{#8q8Q8GXF3`j%WgCs`+{P89z`BMXmGrjZxF}v`FSxm zXmA{Rjo9qhi^7)_u|b35vkuyc&T*Kg80+~n)6w8q&nHah8WOG}DqF37Yf?Uz{gc_C z!LjUfreohCj?d`GQwKCSK8xVoj%^Is6Jc9_(l2!{O~?OCW5!#!UQ4IkC8jG$-#3wtZ|Y6iHHCf8pAR|SXv`e&ug0HN z8s=O1q;JW`zTM)OGhGN#-N zV~$t7G3R4Ar&JaWeQwWETFeFwj?Y+v&BI)1Ko{B~pZ^V$j=&SjI&tJe{g(@G3P~?Ph^jOx-uTGyUhj- zj>qeM)9H^-8E;iuP)vA8qOePm{T7V#rax)=QkgY~lhafCKbnpP=S`oW&G=y$H)206 zwGYo>q@%%k)5H2i`fO?EC{mXH%YCi!B}zMu_p0nPd{QZen@mT8<2trU`FMSNhuNUP zaShPoY{HsZ`$Y?DX1j*AI-8T#*VGLSj(%oi!@^0S#ca^vyy=&k{(#aejTr-rj0aS_ zO=Y5=ux8c1(BSB&-|YESn$^bqD$P7s_I}gR;8^yfrt@nx)!5tI#radGiyPWYjg_RI zfsxK!Qc%PO4)dOUWlz27XmH;2gZyh!Ec$1HRM3={s}mRf8wdY0)BX(pr5F91evtoy z^Dia@{{`pYIQXCC{7WzTH~k?0Q=NY?A@~;;>u((VpP2-kP=Dz~|E4!+E9(UAJD8i| znt@|cZVfhHdYzo%=e5SvvE7(*Vcw7p{@!8wdzIc{tR#I8NH&}+?>Bv=_yJ?)v5y*0 zRvP9^*-sJw)%0%JhjZNg@GOS9QI@w}V9HK4rfhhgAf0w!Z+bz@^#gnAGh)16>02D% zYW%!X+JpW5N*fgu9^@;0ND&oSdE7{LXC9;JoQ!u4qkdo;4dZIBz=p#y@Rs z5hqMk3fvN-qrrL8nIn>OQ=2f4$p#J1o6a1OP!Waj96&Z`aQtir$2)md>WAYU&)K8J zbtk4{vd&mZ_@*Xw%7t@TTo4C8y95dc`O!f^3x31|o$9$dG36NF@EJ;jPciM~xT3?X zKjG<0!+8F&K!I@?$9A*0P75NmdB#e@x9^}cz808{k2e}uD_v@g%{Pqytn^35|D`nC zbIA|-?@g!v;W}mh&o+II(({ek=e5RRO(BlgmjTo18#rEHZZ!QFrHu7>t$DlYXmGqn z&{xss9(B~&hP^eLi24;K%os8 zW4p>&N%}c4+0f^AnU3!b#_aQ-jn`^eZZiI)(olburH))a*%#*ok11hJ4c1aH>#0{8 zvoGEcL&xWJ=94;xem4EBrr)OYAC0jmPuY(s4bNf34~pMyI&};E{~{SH+^2{=8XVu( z`?Bd@Q~DL-Q57kOmzZ1(9zVXq?fL4)Hx z{xos?Od6)xpuzDoX@57J{tVB5WW(oBo1`ag0tMD#ltqK{rib;dbdJ$0%%(+Yi|k_A z)1od7j%Cj>o&8>9Okah0UOtzJTk*4BFA9sy1`UqSSYB^B_OrDuIb5Ky#B?+`Z~6_U zv#&O7i_bS$KhZ`sI6mKCe3!eP)=IBahfh>G*_d&tC0EdugyVq?KEnNu_)_tCisAqAc0p`3r$}#!mLN!!j63l^62<_b! zFrD*luApskPI#5L?)3D$yvUgCml-PwpOeOBqByKE#Q1)jB0BpF^MLqs;zvyXq0;Xd zAEzo&73`l}}k z{8GbUa0za1to|MiHNAaNhKSIGLZ?>=$E$ z2Ioz05GNO>Hq}b7L4)(Azu0u@RgHbWUKEZ~teciWzbH&(xL$OYbkI;u^6XqYY;jsla*uTc?7fV~<_$tR? zeJFeOxy0%H#9_j@Mttbe!kIHCOvZgX28Uc#Y2$9~RRV zG&nw2e9ZKxmHxt*J_zHvUZB7>%A&#Xxg6sr*5U7Fg9gVs6vVL(VVuYhS{Nq>1PYvc z_~)|>%1gnnYZe1mq19{}jpKYi&vf>s;Z?lGg=>WN ziw4JQToX3W>qX%*D~krlIh<_?ZxkvVtyniBVBoyz%$4Y2ZWfQ38*L5@W5CAqL~Qy~ zKh&vCi(9l-W4657m~wNB8Ml`iGdA9B%oqsss{AmfE-@Vr$9-X1|1gGSg9hhK=NQN1 z{#G&dL4(U3_uI^-pcIZ{Z@f0X9D8*vZREJZwB=M|%7yhgov)xvX|UmXbf)9bM%kcG zQcSK&+ZFmsIvSieoqfdhf2hOEbiW1Zbz%*PbYG^2>#Ue?mLfI_lpb$P-9!DQYj>eM zHs^?GTf*W(fjl}IoHsq#`1y@awh-$%SNS@1#uZBE8}k^a+gM5ZIV;)FzPn9_|IP6u z#*}3U;|pA9t|H7@BaCn3Hq+@JVzi;&@KUAMI{l4~hm9Xo zy3*;4gZMl!j6?ZB3*(Rlpu&2^xUVnoxc)O38rdFE*4>snHcHp7H4w#AeS^O(3GKBOO=l#I9F zhZ9uc1jRaW(T})M8tq4iDHH3%ajnxyh8FhA38(NfMRYAY!}oth4)tNdu28Rtjt1vV z_x_K==IqpeIQPYbP){-bgHIOt3I#>%(crx4-e+iUYwGir*oz6FK4Q+5;B!Livq5=m z(BQo3>>C|>`XRY4wV!4>8k{#>hreha#yk&c6m+P9jt1vV7Z%q`_^M+PQYa|Grz#EY zdQPBlq9QsP9Iv^dKGHeFpup3A%1o`=(D3L`@@_)la@lLo9X0Z*-$qw8VbiK)`_t_5i+-$YOP`m#$yiDH{6sooz9KfCQyS`EbIT2;qrq`*p+0e~$h=2cG&tID zOry;PF*ay$wAm&`|GLtz8gsoP#A{7BzH?G7)a_+yzlHvnjt0l~$3xxzn%XZ^QYRZU zIIa^y-OMJ`Up8o={-%d9Y-`2a%nuqI*Ak&VWyaEbu%D|Jg?klYY-d%a+@>_t)7o-} z*`UF(Exw){8~mWbu`QvVwP~OH+-%U`_}PhlQI}brIDXdRMdalZ4UYClna-)r_)mDK zpuldhM}zaGhii(BnP#&=gX6I-C?CheT(d!gqfG-gPwGX1dlL4A2FK@$jmpP$;6IoR z8XWs%nzOmbY|!9n)8uSEW;SSWv}tiRUpE^xING#2n>}WO21grC``G7u%?1sQeZJ51 zqbAsM8#-8Fg7Wl3n{l+yoBkT5^RzAY$!Vse!LbhWolTqBpuy2*nd$FQy1?15F&zz# z_6xDG<9>(PpuzE&E^>Z8Vm4@S^t0I6eA#T!;ApeN+5E_C(BNpZ)Y<&TY|!9n)8%X? z*!hSCN1GmJ^HQ@xgQLxVctx0Nh;9`EpQW_H zxJ7BWzQ|^Zc!ufN;5W?S8pe}gyD-(jEYuYyD*EeSyxy@bUcW99*S!YCp2>^x{T4;^ zH_3mPKgC_*&8Al?eaM*oY%^y6Up1y)j~Xipb0$9V!&~n#`&wblzBI3Q}NFlQ^zkkrmy4w;OsCR4UW(1cbm=- zDk#SDlxcTA0I4Z^Gtq6;j|D zLw(TT_#B&K!}!^wv<5yowdYvIXSp2XI8KDcH3NNJ$G}lIMG?mK8sj0Qi;eMjoiY3A zGG_l;T7|L;mCkc~nQ`zTPKMIDtuQ@|8FAip@(CLiV!Pnbu71eA%VK`2U95bam~e$6 zOu4I!X-lZHbbN0$eW%jx#@thW$9SUB1;*IC!7+W645#%EZI@3pIB$9wZ-c4Lpp`{~ z^QNyh9sf5OZ&O-OOn9SP;bukJQZUY&-k^LklG>~{8#Fj?dLuTxsiCkz5kF{f-t_xS zr`^*O6W+L2_@E;8XmH;2e>VM{N*{E*#hA8KE0!B$6S28eFA9?sVQj;FkhoQRlIh%= zg!?J!aPT=ft(&q%|I@{F3s7vVim_#1@w4k;JWEG|<7d~yoGYEFRhNO_XH;p8V!V!o zu_PNbI9^AnfBZ~)7{jtbgX3q~8?o8Ni_LF6Vud=zgvFOa@blw<>3*?S2=%vdzD@bM z%TnzJ#zp}yKv!=8E`ziY+K11;%Vw^$ z@HsRwHaD2fdZo7+e?jT{j5!w`G3J+=cNtUm3FFVI0ZCQ5FL<%>dZqtpe3{CAz}ajx z=2&bt=A7DUTq{4%8ndr6m8UJC&c-83iBaEV{9~nGGG@QzqfPZ;Dd&|EqkgV&n^I!b zJB z{GUaOvuE9aPc%5%hxcC1o_Qg8i#95(F?%#PZ~D7U|5v56wJp}?L#Cs_(f>zGr#@R8 zf5|cTEYuB~|8)Gg<6k-6>v+H8!&E-{;a&wUC~c#j*UM00vgvKcdDFxHL&=`c^o7s( ziFs=;e8x|_RQiopmh*9*%157XH60C(KJPM}U%lU8%=!C4<9|^)-}!mabTl~n`M&9# z-#;|wTz=g6DW%UEKd1D7akb9T1^BN`+kTv#vuJQUM)juiOZN+%eUs^EaI~N8>@PH4 zqIAA7bIU^GYm_c?`VEdp9lzNzYurWU;nhhEp{R}xjmzxb59R2V+Ir#5V+F?APbkvo- z!*nz_mc7^X2bHeDo{3H2KGV_Q_}=JR<>Ti8D8qiy;P`of&zQbV={oGq=T}WfgQL%H zn$Ed!EB5w$Y_I8PaI7=GyTg7b>Y8wyvv06#1R5OeTTDMs>3V1XdehP1Xg_NDI;D3y z`wy9p21ol1*xZ!%+o#M14bGc>FE%%)Hs3HCG&pbiPSa=V`gK3{HYR^+IvO0uW1T^z$G#cDznE8#Flf&t_~6 z=tY6HaqQ6G_zdAZ(_f=>i?+r0quWeJgU7rdy-T7(ct(AB$`h5;iEGnr@qSH1CRfLT zRH2|4-Qj0@tWiumbQy3Fwn#=}a9*sN3f zW@GF*AJC7KzdM}XAdc@#e#mq*IKIyqo-^2f8=d`sm^~UC?Z0dK9;MS1<9mW(Ehj%{ zaC}d&2^*U;_lrYcDTU*lNxg%v^jPB)l(taT-azEm2pcpw`fqhMJPyDH4URU=rgOZ` zb1bvsSYrIuU75bm^9p0#n&k?{O485&$Ob(;;}R3jP^2t+v$2x&a}lP`cKTdn>@Rfs zi;VFR&JmS;vG^#{3rdeMX8&wszxZZs!T2M@b0p|jrCPm`Ix+W%!N2$hro(%PXl97t(C8Y&b@*PeuB)PRy|-L_fhl4{{Wk z%i`P^`hkf;Av{M~lD2n&@^xZDI9}rKh&vR~@zG_>KHqITN$E!8uPLR!u&3;69BW7w zbq*Ca!M8ZMJJG8>FO^%FFO;zB)Kc~AI7J2G&pZMmdOpgrrYW`unHWrsE4t^fKr&Kn6w8BzT)Q`sCV7c)CcDk zOqitzQ|>Hd{LM4wIL|j`pP`;h(`Q%HO~+=Yaj+G~XV<({bTlQoyy=qQQC78CS^%QkyS`u|b3Lrqlj7R||{t8||;_M6v6R7~3!o z#U0`{MQj!+z0&x#N>4Dx=5)t1jL%UT#)ity6Nh7Ae$I3D7dZ~c#r7MH=?Bwxu|Mj7 z2Iox|=8~WAnyz>2x>649wez=85;__j&+Fj-r_R1VL0_hI(oY-!BgJ5pNU+KjH_(;XD;@5)+cNOH%s@sTORiQl5+r zjui@u$zf31_C)s&geJx0MFGQ_Dq-geZHmbekUh^~QKPU>G2ue0uvjsnf(lC&6BZW= zJ&Fm7DTN`$gi0x_QA~~vm|F+a!3wu2CdUO#?=d;)6z)|_UK}v=Me>rAX@Bz4lsCgP zRN*1T24!r)cdqnNxBN}q=(1t|Uhmt<8nK%`;!)*a`JK;Gg?}9mT6!yRur2I5IFXg>33m=7j@I@)-G~Sc> zDNlqiO?eW$AZ4D5CYPmLfG0h57K+DKCVX02LO) zT+|en!c0gCJ@B}T-Uwfp@+Np`%A4Vi zlplhZrMwO9OnE!pmGVxwJ7r$u91`Xk^)F$vV$>Pdkr{T8IpmQ!43X)Y$V(mf!P+-r zjbh|m9pCAgc`({+a=gXyHn>VJ3Of`d?{fT<dFwRl>l|}S6ZLyxo0A`K9L_bmwXU#36m^l(m@{tWuW(Dd{? zGOlJk7*BFM#c?BS*Mb(uZH^Z>4(Em0cR78?G2amoeTMOG*B9PXNQ}dnH|D*AsE2WG z*C5_2jMt+uwoTvd^rs#3ojO~`yBIm zp=f`r<2xPS58E|#ljALpw>jS7c$ed+9Pf3!-|<9^{dkS$H#Z^|98YuH>Uf^xg^rgv z?r}Woc%9?*j(H9r>+k?d!jPX?}`& zjpNCV8yq*mb?F>3+wpwIiySX?+~;_W<69ly3EO(_e#e^}Z*jcM@eaqk96#lFujBoW zCu)w2`{g$rA{QJ_bKDBsT6CV{g^rgv?r}Woc%9?*j_-B+faA@Mw>sYL_)*7u96#fD zpW|xH{jn{R98YoF=(q*8wRfB21&$Xx?s7Z?v$#-L>-aXu8ys(R{2**=`-dDq;&`Xy z-HxAj{H$aCNhbQNaXi^^gX1R0vmMWOyvXrV$9<01IKI{KosRE^?fzwx<1LQ2Io{!T z7i{-CPdVP}c)#O`y2eI(eitHg0k(UkX^vYR&vU%c@e;>9jz=A@bG+X1y^bGnyxH+q z$J-r0>UfXiXB_WyT&?v&Y~v)yQye!sZgJe^c!A@^u-#X7IUaJn*70qQH^6ouy3z52 zjvsRTh~u4bK_{2OZpTkMe%3J$7m|XE6>8wADNlCX;JC^0Y{&EA`n2pK$4edeIbP%V zR>yZbzTfdC$6Fk4bG*axF2_$f-s^Zjd}3PXiAR;V&T+x!QLt1v8Uf>w_3%ll&wCv|;CQp+t&X=le$??E$Im$4=eSyH+qmCJj;A&&G7>Gl(hbf z9d|h%a=g~@ZH_lM-st#2#}7Gv#PLqYyB$C6_*uui;TP*%<9M>;2DmY8SCiw}j^{gG z9jz=A@bG+X1y^bGnyxH+q$J-r0>UfXiXB_WyT&;VH`21~><0+0C z9k)1cgQutcw!raX$6bzx9IthJo8t}ejMV2w#}7Jw$nhhNcfx0+Wp_J%+VQiF`Cv%2 zuYsG=vXdP*IBs%0+wpvOW?FWUm)V*5t&-eXDE;yd%xYhAI#|z>o(-siYl_jB<%@Fd4m95*^{aoh&mbK?b$7d!59Jmh#S+?uxcHpd$rZ*=^i z?C>>G*!fn_zpEzQyr2$2%PFg3nLu^OWPgj`usBsC(IH&v$YsZE4wp<7tjt9nW*T z(D4$-J@A~==cwa#j@LWB7oMBiKj3(?>o(-siYl_p)(clN?WR+z4Ng z)~CgBo8twJ7d!5P=cQ$b9IthJo8t|RH#&aM@k5Rual8|LO}ek$j-Ph?tYaSZNBbJb zlN~oWZgM=^@qEXN94~d;2Va!dZH?nw9pCBre#e^}Z-M8hezrN@;dqzhryTEfyx;Le zJy(c6`CjeF1^D80U(+17I-Un#lG-eEyu@)2d}(Sk>Uf>w^^Wg#{D9-l@PgFOR>#{N zKk9f7d|7J$jN^TdtM!Z_+Dvjh#c`wK7RPOl7dT$*xXba7bIc{}4&+$U|@^ri{aopp0)bTpU>)|WXviCZE!0~3s zTj7PN{dUKXI^N^>8OQq^SL^v!^fSrv6vvH@TO7AJUf_7K<1WWT@Rezu*E+t<@dn2m z9Y5&!A;*t6-syO^zEJj#QM}Yp6s~6aT9!1TL0OO=R02Hc&Xz)$7|rLQ$M#l zzSHsjjyE~p;&>apDD|_$@h--0FB9{Mxh*3mq?U z+~auE@jA!r;cHVr_d0&S@n*+c9dCyhr)3{?yvOk~j`zW@OYN%*C7$GXisMGdE%57e zA+$MO;CQj)F2_Ug8*(A6b$pxS4URX$OL8GR==dSWk2v1xc(>!H9Y5G&pW@JlpYn_`1}7k>jO~`y8)T{RlryTEf zyx;LeJ-dx%`R?$@1$bHNbDHB;$MYO7biBlI58Rph8FjqQ@p{MiI)1?MX2)9{Z+HBt z<2`U!y5DCU?{i$OXTZ^B65O5IPjTGnxW#ds;|1{YwCrNIH{~w4FXbV4Am!YQksJF* zJC-RO9Zu7pNPWGd-NPMyGrC8H+E@23?`Z1J&m8qf{Fwosuu0U7s$Uz&^ zBQ>~uv}4HnwVcbo?vCO1h1pVm zjVuM1=E;6V8kXN<*2hc4Tiw+|YmW35z$baGCw$L-Cf z+Ke%zuAM7~hdJi*+UpuN#xCqpRUgNVRmfjn#}sGUEfpS6tk6buaH&*{6Xt;`^jj^I`{=niX6OcdyWuw0pRH z<%nK-yLBcFtX!_;*2-b!bwOD*=F|&iRu251l%kfllT00G=lEMzX|3ibh)@MLr-$>Q z-(S3gMbYW<-ZkA_?ZabMa>1flp%=CoSvhn_4|vy-q~EXh#?~Ti3_db*)!3>W+N{{^ zVF5dI!)W{R;qLCP!Tv)YqeB`OM@a8bXPE_UX|t_$+j~bwR(7|Ky9iu8)X^*(#_RBC zw>v$Ho|x)_73XmGK*zGa?nCW(jJbCEg7&QK`&abSH~oil%m5i3Sw8NnOq<8tca#Qg zu_?I7*o=0s(Ymy&gZ1mO5uLEZ-F+Q1P%F5lDPw!kF5(SK8QU_qHD#>u$ZVoZSedN{ z-P)9F!bm;n=BBj0*e#jcn=%%hdc_-@aki)TF=aN=fN?j5aaXow=?Z&zkYiIi7Ir7X zo#@ONGs_k%-mH|Vi$4!ao6~c8?Cnr#Yq6g?%iIu^G4r=XWj5nipto8E@O%u zXIs26DzlkG6=v6QwvD}xl`&%9;~BB-pc|wzKJ3EFo$7d7!*1**DSMFpU6kD;9qNFW zF)zPg)!tu-;!RbVDpI=&P3drNI_6fX0@p8OpYdN&%k1{*h4)_GTlN;~pyQJ^Iov`W z^1wK|vU{>_wtKOIXI*!rHBMU&Z9(4^SF+=HIMnt~KHhSTSN;&&DL?j(YaAypXjHl} zE8~IPxLdOqvIwh>ag6-kR~Zuy*bA6Y8E(7w zI&4suhxe>n8bUdd^wXT`UBnR0YM@wP6rjSf82 zws_N*Ddw+>xX&z1LUoI-{cT;wPqAv1*pzPm#`EHD|1vhk+8lIemoY3>>4gl72eIsZ zUB;_Bb}wLF96w`k1WW!(2IJofmaM~}IOt~ZpbP&Y?gh)7+{G%4xhXv89bU2yfai!PYo(0pcVxU-xw*w>Z5t-XQlZohIBExpl8L!BUcPuG}t?!$9&-iXhr(&n!onyc6CNLY(1-0 z4<2QpjHEZ~c3*{JMOX9*_ zkrOJb-zgQ^U0k7EXN7j_Dzv+=Lc1?jXt$?AyXPykJHD#2etuPjb{!Sk@tw+*j6c4I zxDvZ3DzrOB6IUhvW>#p&cLi7C?;k3(`(TB3;kyeoXT8w;{Id%E{jEZ~mmgMHd(WxR z?%E3NR#s?tPla}$tI+Nz721XGM5y3+)aig#GG6!|{z~i?S7>)*g?4vWX!r37?Y>r_ z-Onqud%i-u2EL!5g5z;ng?8aP7b@`gz6$+qsnG667255u(C#F@yP$%0Tvnl7Uxjw- zE42G)g?8aP8!BkWZz}XxdqidZ@~R5$Ix4h#ONDlysnG7}3hgHF{RI{D-;@gN&aBYx z+6wJ%tkCWQ7218VLc7N*vBSWcPV-J7JWgPuo zobk6y+jv$GL-faYT6llY$X|nu@Yka>`Wwvndsf?yiO$T9?DZLclWtGHV-SDWn;q@F zJ>#!h+vnoILag6y8GnuP*C!kNk;eLcI^&P~_2U&|i2feT_}d_VeBU4b__%iT_q~ii zzT57aGX8dC{B3);+N;5XKc3=5e}BsO+bWypSUIyJ`@4+4U3aD5!Hd6Pv!nlxJ9_MR z;rrgowfAV*QHM4~!nC`^Y772Gm5=pn%J{3%db&20NMEocoSyO5x1n@=S803ncUi_? zLH;!Kiy``(pYeCA{Oy$$^;@Gf`dg9l$9JTyD0)ln$S%wH8+}jueUbRP$@%*S^B0f7 zaaymw!ugYVm>BOo6U~nwl&j^I;{sUWoH(m zzt3m^QzRXZ)>| z$oF5y5bJkS#@~*O>OY$|I8S2#eJJB^pZfj0GVOhT#^3&bF3m%?JAYru_~ZLs-X1Gw zc4R-B@mKfJ^m|n4zdOv1_WnHMZ=3wJ;J`v`?@u%SCT%LsYntMU?X6aMnit2*v*gRP z_dv#9m;CLK9rfecbnL$qGye7+tKSZ`x{<{Cogh274N+m<$I{weY_PbejTg!~A^_l&y{kVS1 z$;OpV`Qm>6J>!q>te92YYidV!OU7T#r*gTa(rJfI(W1YnGX6G>dhBP^!M(Jzb&6hzq1{GA2B=peJSJb8TmU4 zM;4+#zF!D#Gkw4O^@;JPQ>s|MCo=x{u81Sbw3qK9^8R}MO}|SgJN)SsDEeb@LGflq z!gPI4f&Nvs7}!QU&FtbhSRlK1vB5%Y$4RpD`+Y6 z*uk&K_ zc6>bJZ-M-sRHk1(lJU1g{`ekfjtBEm^!M$IKmK?Bd~J^**6-^Xe>=ZWn#VsUkkKg)^A^Q7e#$Ur1)8Cq;eyVEGU;enU^T8DTPxt)j%E<1d;kx_W)OQm&* zs#^4Sdd6Ru{OOWe46%MEXZ$@afBR)c{kAHN?G4`trF=NMW44R5_;s1ae%+CD~-ovf5zW5`8$mQ z7O*4yCF5_i{4J7>zwJt+zgO0c9e<1EZx#+LM1L=n9o!c6ua>SK-;x¬yEuejI;i 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 literal 538112 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≶j=AD6Ns}FJHsn7ns`~7AQoes zxiF0jx|XILYnVZ8CsuUEjxhpfUDU7%i#$R@W2P7qNUo=hTVT?fZ?CtL}~AIDmUmUPD%i`E441FeP=h_a9eTn{IZrzx>D zZ-VF47khrjV(^RwaRLpo=Hy-yCy=Ez?nQ9|v4NJwiA57Hj1$PlEOjr9u^gVrb1}KU zaaPITZ~zv=ff_)#|8<1bBV!^C8&_e6YE0}BFB4AW;#RIav9!ifZajc`Zs)P|S;#Bi z1&9lH#htevu89YLyy6Zt&hqyARt`SDH2zS?f6f(N;0p5&Fiu|MvUmW<8+#YZVSD?1 zivXX0-X(vPE4<7VR`-cYU;lqV^BT=AdESY~$!oO513+H!OMP*cSN!+39#-!PI6SZT z6q&hm=?KGwtQ;sGK5C0F>%uJBh};jg;Fn_S_qxxzQP!Z*9ZUw4JS z;R=7#6~4_C-s%e9;R@gB3g7Jtf7=!Qjw{S}5#r=E?u!S2yvBA{_(50rd#>>JUEv?N z!asC{f8+{3;tD_J3jf#@{)sF6Q&;$BuJDtt@Go599#?p`EBv%8{3}74WDo)3vX1oHN~^JAEI$8qu+yu*u=SG-4{ht=Jx z!}G@OoK={2_;K>a?%o`pH}>wW3iGZwPTtu2mk!U{@4wM$FYf^3msVRhH5!hF{uPG0dYoF3+TCUNq{-j8#5Uc(=M2;?;auCVP2 z7r4TOuJ9OFSiN`Qu)VQ&wp2Lik{|C1PjH2K_a7&(_{B3l%=cj8{kb6%Mn<-$-B&<{JR?bFhBV zYmCoX;(X2v@*J#ZE|+2UgdDtQy-|kQa&xeriNIIH_#C16W`PsG*7&7*2%pdO5t3ou zVuqiE39j%ASGXEsjxsFy9Akme z?0WtMSNLXxSza9Za_~;pf66f5WXZvL?5GU$ZG;?@W-5mGxcn7HkqmR>&B1zXQNQq2 z#`QAHkva$8V)ShpW>3vA>W!bvFneMSey#YZ437}uX2Xjqgy}iyufYH0>)|$ozljuo zevPrdUwD;qhYUOV))-G9%yMMU%fWi=MT8ZR|As64p^WdepS8v)B*yeI;Bv5D3(K(6 z9i!qitP!rw4_sZM;SyuWGq5mrR|CL&Dv%iwa1+l;vg(_TKyF}51l z$S`N39DK{y*QGp1@*I2vCcjIK@=kf&Z5%+D_B!qF+s3JW^4}5P9Tu0r*SJ_)QZUWA z2s1us-W;qC)pu$+?RC3xqkQg!A2c39nDHEYzGwWwrSCNkS&y&V{8RnRhWBkHs?-%YdZj)grz1_y6GE5!W#);@& zglPhQM~mSD2&0QbmlHNtI4>xz{=!-#cBY{p+4g%|3HN-Baj~;p3dK}$@9Z2x4s;U~ z6Q$T0*FWy3M*mBo&THD*jmE}R?Z)-Z?QzR^_JBKB6sCcH`NCnXMU5?vql zlcFwhXL05U{Qz?MMNwjr{^$1nWJFRpD`K0Az5Owegmw=!kcf8q(@#WXYoHsSGb9sV z^PC|jj6d`4qo169q0{dHEjsfSr=Q3`S2v=spl7p9I~|7s9%A97s-K2LmpL&3eKr1{>aMGsxFKhG zmhh6MUrhJSOzdHT>llujF?QTIjuHKDWMcUl@UVgXG1VLymO+dXs10iPfL&b|lf2NX#ykZ5V#WJxELl17V_9f!N4I-{RXrjjNjC z_Oi4Fx&n!56^&882^3>8rn>BiF)`k_uQ_7RVzunL+Ysvn`Oceo6t|8EyRJB5>IS&i z(4Qx~%!moZ>~Y;-h+1H2b#!q8ZfM3ZcrBK3D8zXyI*es_v$^paybiq#D?I!cMz`?9 znlcxA2u0>C8lMY7N&V!ty_mVh5#Zi|zavW`PM3V{$JF<;b8SgX;=YZT>t*i2%x~cX z#PzIshk#;zYToW(s#d>!Opda1GjJ}}_B_$OOJbh3@Oj!f1y*Jwr`Y}d0GKS{>|{YH#2D9KfR)ViQieQYB~zlwuzab9JYpp?i89~D2WW^aAM%LPC4ZFU^FRH|@yui)fC?m^ zJmPf8pMkI`uNBIq40*)ql0Q@O*#;^p&%y)o_i$)urNrryKNDedD?UJrr3`t*>5|Xy zNoHKu`SlWi4gOaoW_uv1_89=qWkUkZf+L;}-v?(#@BtEi0etd^(keqlD8RDMMa4T)O1*nMzC4(Rt*^_5ggo6O7p=WVEXg zWwYS3;U|(;6@+K~(vr$W+XJRrRzt4D%)6RXL|#6@oU)jDM&ko?8yxYy@c$|??Tt#@ zgZ@4ljxyx)+?JT-$+JXarhkvbwCf5u@;MVPmDq>pUy}F+_!}j@oj#oTGkk#l1CDXY zBTkomR8MS-{hgE{k64YduSouSq{U)YaV=HKxF`k9m= zk678mXXa1&>6~%qUJ%FWl0O`*T)$zAbsib!FB|}t;4?&=F8K_rKEn2w8z4uH4?O~k zwHEn41lc~)C7(}KT(+%Tn;hpqWr>@BC%_TUhA-wL$^W#*ua=ndOvC&oK0u#^V_fox z($vPek%5&tX@|vpXq!o|2gQ_exCpKS@meqK`|RQOSoV?zvQ2{B{On#?6CcnpNglD%Z%cjy_Pp(V&I}aqbV`9pRwhGL) z@Hxqc=gd1&W|ibqX062Vj13Y~kC+Fg9=0=;)&rW%k0qv_pKCI|)?_%AF>WpVizH^7 znxtXTuC{>zngK_7@`%;E!1(01!@o>owy!HS%r>Ov7nU#O$s<;J7@z#x;jfdp8~(p) zShO)|&t}Odk67tpeClCaW3wZE82Tu$ZrzIna4?nz8p2(MM0|k;#9&x`qlKUD_Rz-LS66y9jI0s%X_~a3%OFo~f zxsT6s*)TvNZmNU%sbnnR+=&if*bGcrVKZ<-o53H{W)2b{k?wCDENlj!JYlos^Qn2j zk;#OYTjF3*r@$-&l9FNk+)}|3AN}|tjem=S^Wo)|Iat^eaj>XU@W~@imweH`z(?^q z_4Nk;5W64sFz>|alFu?!dvL~~40*);_TVy)e3m;2AE2Rd#3Mu~UN0h#>{uWn156u9 zCI?=SkeT9Oe)i)})%ZsoEXtOh3`CqR`3$S}AaqV6$N8p=TwsoMq<%8f9o`vy4giwO zV-67ct%&1v$tS0u&Wjxx!S8mku;-Ei_>~%8*0qqY()gHzNuu9*9L#=gdL7KRWik@T z4`-$j$vw^x2eUbvQ~+Y}@y?%A31^-|584lBveSSL!I>NwKu6)s(L{!E9M0tA1L}h_{rCXA4`;Fikx=%g z?LfYlWpa=MWf2!Tm}j{r=0}pBm>mlgB$jhi331Tjb02DQPy$sFV@xL15X-T5K5>!5 zUqUR$z~#gf9eyh@#v)QXafySwh~?O_fmn_wHxZ*>lWrxJ{r4_n*-sLHf>XfLtsJNt=ce>p@f`^8aW*%yuzS2{ZTh^rjTPZMDho1nt1euY`| z3NzcL>=!dMT%+Md8eUE;`_4)YcWL+r4c|)a!v|;^oWi1gO8(;-zlT`%!Cnm?((o%9 z7Hv<;pC(`S*)*1k#JL*wYq&_mw`#ak!yAa@eAKPsyEOcO zhWY#3YR-C6!+gI@@t@c5QDQl-y{X~%HSEK9pk%U$IrxF{HO$`)R{TjCt|XT8W37hy zo~PnBX}Dd(>xt!jdXt84*KkC`JBa0+%ijc7_-PIA*YFWyIWHgA@JS8xUp|zKMJ(s; zks2=4aEXRzXt;)0&h?8lyj;U8HQc4)8#H{YhPP?>Aq_vS;T{e5YWNVbTyMOh;XVzE z-^rCSX&6&YKPnx>dq2|;0P<_NNWNde^;GFTq2Z@B%-{c0GDkFgT*D_d%*~RLw=_Ib!-X2=Z^F;2O4Y4`>W->Ttl8h%K_k88L`!@U|lq~TXI+^6Bw8cxH!t!&HH zuwTRcokt~8uHl))W1W1>*YHvew`#ak!yAalIdQu+e3ynF(D1{=K}Y^c4e!zJ`5RgD9O@8qOyk@1zyf@FWdaYPeRzONb{paho*UuHp3>zDdKk6JO}Wjc9m> zhM&;z(;D7ST;#+(qT%BjKB-|Y`qh5N((p(P7izeKSni2tXt+khi!{7k!z+p99;!>j zH)!})4R0gnh6D7Fh9B2(kA{0Se27@?%U;oNpN3CsI1TGWwRg+auwTPP8ZIZ6`@5MM zp0DAh8g3<)d%#W&Z_seJhVRnw1H^LA_^^hb)bL&nKd<4V#Bz`MriS0wun%iqC6h%g z_o4Y34r+LkhAWB7ojR)3@DdF-X}FzO?q}C)_$CeCuHlG=cM!|{?-Lq+TEqJ_e1ur; zk&kQmq=xw~rb@;l=B5@jQp1HBE+LkC?HL-b(eNS-FDI7!@s%3x((nx$zLi++*|%x< zAq_vS;U3~jVY1Py;X@jJMZRgU~=4X0sWqWFAYMqxj3wIiSGCzq($UUF$ENH%*J zG7K!e11(ia?d3x_iB=IyaP-oA5)T)Yf4h?-X!IoOH%HmB;_V@|BSL3 ztbVUdQtrki_ayXXa-W-o+~g$XmL@6pwIteYq?{ieH<@yoounN9 zXEYgo-%L{OXGzMvoTOY9_qs{6gHIU?GfBC7 zl9cOBQttI6<<8|kHi`UJCMmZ%NxAMM<^Cf{x!)!!_d$|!qq)aTqFm-ADR*s>a^D_A zjy93*lX9581i9CVO744*LsKvYlY1mVx>&x(NUb|}K#sUlK6&y|=bZtr3unUd8McPT zpI!R+Odh8K#n-WiUHYEa^v#xX)R)11H+&3Rf|lb`9zTjO(M-@N5j6BBk$QmpOy}oFb)fg-c&h(^m^&rEi1Or(Utx zi)ZpEUZ`YQ(24U7_^Mov0^i36l2p3ibfsI1ba~&yd;rGMebSYW8z6JJQYPgX{E16n zew}lFO??Zb9P90MmpRkysMps=ZaWnB%YxWS26(VhQ2QN z&%s>_$7ihHw_N%*;6b8!i)U=QJ|70DLd2)OwQx$`c_=Ksej|90jpvFeN6Lj9aU}zw zAoQv6?>dB)zR$Y!J&p&7=Ka|&eU+NN>ot8}cIkV10DU~e)9qWL>077i`%jlX-cKi5 zM||IRV zPPUh?OF5Qb20E)=zaz2!l}F-K6RVFj$kEnHGC`564P!Zc=Jy+LD!-Fm`j$XnqVcc9 zrH}tmQz-R)Q`5K9rH}WG^?0sGmEYwqeTC4+H81VE4Nlp&(WUPY^o>-?q#T1^cIoSd zz7p`MZ!4VA_am3SKIj{Z=Zchl|KZYi8v3~Yr@lMjl)e{S`bJ_MI#nr?at!|7rEli) zczxU{!b;yvm%bwC`?QGRd?@=aap^k_eYZk{_I(dd>HD%vUn}&T z>!=c+N?(^tUsprC{JyX0`@T!x2Ixyv9}l?nZPWDqK+|{FrH}X2_=}OU?|GNL9_Ul` z@k34D`!0RF>rT`^{^8PhNYnQtOmt1db24-=L1QCGUHTDkm8OE-H&|9UHdzC`W7f*ftAgd=rp z`FIjxK0}cjO(jK%ePA@u~1LGF>IN0dgKqPT`kb`Zhw2^SL6W?;ld1dPX_U z3yLU5cN%h7%EjmxkSmXc;rbq-_aIFj{1J1>BBN2R>suwDL?u-;wn=1(N|^3XO&a121JAYEpRs+ z?V}k(;Z$7!8b@au#t||lDSfdo5X1MPwM|@eQR$Q^lSAc`rcN&L`|$^IK1)kVrc9dT z_fIP+ol-9N%g_1BtlHV8sWdUqSNAL9ktKKrBPNM7gZQ89(wK0$XP(Et&vU9^ZcT1D z*BJ7$XXm7gtu1pxDc}xyxh!xh8uZv611!l{L(SdiOK|5Txuh^T>7ux-? zh(9#&W;7TA)AD5WsoY^r=cy3-3n#Y@Fa2k<+#B*5M;1X>Sys#NK;S(nvUB#?i;ZF* zbUpR)sRAo-0*V}FTvyJnzM-YC!~7`PgPu@od2)7T$%F#YsD041JzWTURYR2~Al|;f zu75^{mhL`chODl@`_WScIpzn{Quh^Vj>Fjp zK8)@QSl(wn`A-*T3@tT3q=t$NbI2h>(KixB@;;OKfF4;2|*j8FYb+%od zV_PFTs3m&cZ zRMu_UQtfT19#L1F$AUSOtrd+dS$ch!_>2>m0Bm6Bzk@_Q?+YBPH(xhHDBGM2^9`1C z;N|G9m!j72gGbC`9wRjGmc_)?UPUvwypCw-KUs1~&PBEt5ZdtjZm961fMtELV1)5s1mt}g~bV^md2WWuic>*6r zLmngW&*-*=>{x|a{zjwpgJ|e?X1IEt|Fz-qK0*0ULZ$zR=Iq*E?%j9a&_@p6_WD;p zxYpm(8OAryHyYE-Q?(hTZ!(oSZ`DWMmJ#O!O(X^j_KY$7`#b-5yJt_p2)q)ta>HRG z?CsiFc)3&Br;1X{qs;F5KOcQFtM^hC4wkNEwad+$4R+wrfy ze{IgL5;-1}MxAkHn#U%r_h{bl(n?Q618+scXraEY7ri^jtnXx+llLEK%q2wT$p=&NRRYdUl4+4g3ZEiiTlTe~y;^C2FNw zVW$BHi!CqYLt&pi(Fo?)yUm@pY`DCP*|I-#k#^8R`>uR5dZt!UtQH1s@r zXV+W4Q)4`-B?hu@*@p`4>aOkz+gsHw3gV^c=J7`0SQPme^Y*w+S;#3SPN$p>MbV4R zm)L586K#8R_oJ4t!pD(QjD_Is_Bq{^&~F}gBt!Qbwq4~f$U2g<{vV-v#wyQMST|I7 z%!7O$*e8n8AJ{93a%6B~)gI2sDC^Q+p-AnB&)nxIQe~Q`2=!tZ6k{NJ{i|= zaWo~bC~XTk(}a-5oFNLSHL#>~)MfMMcLp=;gI?Qn;_~}<2eYjUV8kArk@Z{@sk1}d zezh&LA_ZD9uP8Nt#Ufi$+PkqL1xhgAUx(IP@BV$|W(nG2PTC{=20=C6VO>-u zCKJn3Qn)FjPw$I^7O*DZFFA=Z2qhlIF!{*7`<%H0>%F|&GppW?+Gv%YE_6XO%RQ5g zy_2{mI&Ho5dNlBAv?jC8XW+r+i;TLWDm29#U-fJ*GQ!V$!@d&`9JOfbgIot$=hyYF z&wI?b8T*Kyk0POqLQif&Iixr(@G49PzEC8BqOYr$GetP!k(D9J7co#uVy;+X9(>l^ zzrQn>>6G*z@85x{np!x$=Xa4%ap=k6R+HVk-rU0ywPr#sB0kLk^g%1@cb5njhlqbE z~e=7GRAZJ0?K67^U96s=(2c^63rDwgI=ihmK*9VUT{u<3I^9Npw?kx6f{#P22S9^iK(HLK~ z_~(}S8V$tY@?tdap7VpFPds-~i|5>;nH3qIo#>1SwZ4iBH6|4KLeHhe#soYWX7|d0 z)6U!yifpxOQ353wZ?JotopB-bXRqyDYUSB0N7~-2?3MYpcbUC%wC%mxuI;o(&$E|K zu`_SAYp<#EF1Ikw&Y!(CT)RH(t*>m@)KL57I&VWm{w4D(ed}MHzc{P%GJoCDOTym9 z^}nmE^!3fmE}5KFiP~Ix$?Q2Os=h|!r5~|{9mLM7@6O&7BvA5l=Akp1?H`MT)tpxC>>LnFl@C$Shuzvi{(>TYRZFMiZ;+rV7h^mHF-srD7;FS}xAU3dJH@ z%tpOAvqu=tWVGOgsD0nve1!TC6OyyQ-oxXHmeFZg76zV;rsf%e-#QA!-laDT{+=u- zJ{R+~Q2bkwUI*oSqN(Q?W-l2Fc0>JEseUgxruc-I<%xIP_%=rL+q0FOC>v}!um|_l zvoB)y&a3vB?@@UL=khwPS}@CC!8a%6!m#%?%kxZb!S3qYO5ei91Dg|U4Y;MS?8p#j zU)UQqUuSfE`>y6c19X+PpIVD(OWKA7Sn83-!#e-WckAcX`>y>62!gOnQFB z#=wziO{ljsXzvKwcFDG5y`wP{2QSWlr8j(eVcKS|vEqUBmYlSn;_Ur)Pf6%jJF<5| z!NV2V`^$Rv|1RP$j)Wpj&TP0DL-_tF8~3~sg&{C5FZ_P$U!!T)?yWzx;CR*hr8&F& z$i7+|#B+}J_)%;viYm)%Gy@-SSr@`&|88_=!4Rh~xD<}>V-xLdWS{V3J$ahNhCS|k zVvl<=x}%`<-6$$vRBhMJf?QNl_nSCh3gs9W4=Q}2rG~TCmIn}t>^xsLI!TOqVLbO0 zv035p0WmKe$4;XVOBegkBA>5vQr>fm5ekSoqM#r&+{i01^0wKPjmF$;XURA|(7Pj; z?RR#|n^10lik6#pj?uftUTD;0SH3oU_P-j4SYsaeeRNtW2CPL!-S+q9Wmwfm?QHXR zPE)cn7H=FP)tIRrMq9nJ*R>~>x7K4Vzq-6Pj9qYO^)x&YJ<;;E*6+cgYhPhxiN{VY zs!J)_V4E8*GsiucvftmCI>Z=NR#MVgQhD-^lU~^KVYII8b`DY9#ef|)hD=k|u}thq zbKk__-uh!DmA+6>7LHdqS*^^1w4LJ*`1-=x>kne1QEB__m09JP>mLslTebM4-l=0?Y^((9w)2PT+bVW_qK zrUj!~cK6Qz?BAFBJ8yh+(Q^OEKR)W&ygORD3R0z**}p)!n$pUW&SLM>pPR)Q=0BFbwE2ywYld;wH-@Cr zkJ-m?2s5;_^uuW0(*_Q`x*MGHNz2QVqIlo>-yFw1?(vNiaz<3=6XNB=u=SOPgTpqDHf*b^w+>dMVnnL?WfZe1g?ute z-(1t&&9)KvFTwZh{~eDG4>RE<9;={aGK0bn1gllB^bzh&f6Ry{V8P=AHD=%kN;e~o z_aRk`ll`|S`aGzeD|Ro$LA>ReD`q`i22=1yQO>?Nd%T@5XNW5#Datj1H(Lw5Hn=sV%5>b{qi^>%dg1V}HyaF2;U1@${_Q#v2K z9-UoCHA}IYF1D^PojKkvE?HvcZA>js2}k^2FSC17o&8U!xCC28%Q=pOknOqs1CBrf zVjW!s5W>9WEuYqFd#tf`#@NuPmYfSQ{>&}Am@o0b>e&3xC{5WL z-E2Z;pz_uCDaDY}&#@3pit78gxjuZ`p|P)jmHX=tu05RnmZxNX=eCU9*ztMo-hW#8 z{-?HL6SyxMdupznUW(?uJPh0EofAE?D~z$%oi}#!sIeo?ulkEP#maGxcu;Fe+oA_rZ^i9dA2>X)stFepxhh&V2%&isp~ASmFus@0?T@|t<*fgw$@r| zr*`eM)AjRh6t+0wZkcgO_eW?ItHRjMiX)!QDA3;3;#>m%V%7aN9^gdhK6*e9A7v z!Ah`Vqwj>37moCPCTtD)PAYQN9eT(YS+{jm%V%eqDQnacLxGNN)1 z&I6!m?BuldCr}gfcjsjlKA3+{SU34{%lKHG7cA`_yI6b4~@cb8H#&lX-INdDi0` zRH3Nzc4UPtZ(em)*z)DQGVC*D*1I@%O06)iJs!2UpDrJ=#F|jh>bd+|!*OOg=Z=gz z+f!3yM~pdlc=nWGt#jxwr8aT4n?hzCveh;I}e|~ zW>ZBFvfkhJv#}yP{kP`*Vi<3Od zS2BB3g(ttme1-+%997{wC#AJtq!RR)Vq8HC501fEZcAOd`EwyIJ`X%LbaZd2fJ---F%^1Ul6v8FLExk#3F@# zA<_C@uRW0t_kiy?jX+$voQUSFO*!z7C>8+Doy*RG8sH7RX3yTz;~uoNw?+HdetN>i zpDyazy}f65Ae^yocXf(oS?3p9mBpLkC$ z)_wQ0R<*TJ?ryAac=9^_*^p^gy%@dl6w0*jy9=%A;$a(c5-W}!ZZelx<3|QZ9I;EE zj~1tdzq{DE(X;O}XOA-G4Xem>_BcW7M4h=O(uUWHtK$!>Nc@zJ>$I?B{&i2^FaSKefQJoOQ*s^ z&c3EsZBUMln4-Ejnc^J-<~iOf^mLT{7*G)%opop_TJ5%KC#Bxq&ZvqL5^=zycIhgX z<2!r&pg6YOjbZ$t-?`Hi12XP3c|9x6I{3;(zc(bXj{O)VfMo5+N4zG-(P9?%Fy#f~ zhNp!JO2!TM*xp;!$qMdd$9tWnqeytLFomixwUXmSgxHVGTozK9!4W7_*_?gW+D>>GB3H^6()~$&3xtD{y!U3Hv#}T!TjX zrq7sO!R_z}`?+T4u+F~E_v>dT^x76KZo0B@17zBlHsJ@e?+Ze4F}CI)^sC^ zhgFW*g!{Tos{vWRBD>8*_RTjrrta^J*!NvHq4!uVej02^HpFosQn?JrzVlM7V@}?j z&qO^-GwA;@#QDw8clN!+Q=5|goo{(Qc*HpredkZnT{wOjh8y#P)%V&Ka*sKA)+Rf0 z&xA7TpffNPXFAjJ(W|nrFkiTA{$+iw!;W5-J-*bA+&W>*gt7MS+=|R1-xUkms>TQ8 zwEUcZTK19!tyM?r?8w6u!XftVTxVcvt;)+u#q=DByfDUZ_bs<0)9v!oBA+dXA!k@@%0B=iy>;yJUeK>6>s_a9EKKr}Jo>_U=*Ue==@Z z1HT%J>Kt%_?=^U@^h>d zyxkMZ{PMh%q8#T`Ug!-)3@9$C_J<~3P*hh^l49PW(v+$uUNFy7QkqiK;2g|%!N9MN ztH@keWqyN_T~&+2W+-6V&s>DQVctw$N5Getpmw8B);3WMeq3tkApa1=IdpFTD8 zR910HTb21`nI22IJiD@a(>z|ruOqkI3=Vr?p;KyChQgUm=vfmA@FL2SO}4eJ;kjnD zZ%MVb)YYdn)ceepj2A1*)~YLQt7-WZzrA~e*&-8)mBlslQtU{oS+DpbEEe)SZ}~7g z5}8nDM>5UNt7ocQn^>-C=3>Q{;hfVyteycAs4A%7!e_5A3o`8nnc$|LJC-=T@4^KG--Vcyb` z3iY#`(Nzyzli36{qp`;Te^s1ruaPLXv!er-WbgeCoVqQb8ktgM_e9@C)ln< zqgY?mcteo~rcbK7Z=~gGh(uxFm1XnS_H+y}R@^!C!kOa=-yWBnlF?`7!1a3_P-=00 zJ0qFBvRuo@URUCM)>~1`I5nA8YRG4NITce+o$nqir=(+3#gNONG>cQQj~~+D*<4{9 zc$w=-I|DBOc=k*)ic{vASI9fl7d;-;@qS$GV3LJz#q+xi~foSQ0=v9^#T4y>}`(5VoOgr=5XSR572DJOqdw>0moL#QQ zjAD-oVq&;>{Ae+we0?Ge5EsvwNyx9|JYzq1k#jO+c}ky*+Lx}u9ar@&OS0L@FSGeF zOW*Wf`_e7HzSxdz4M$Qj$4r=L?iBUte2U|tzSo9}vkLfD1}2h>WF``1|61`56ql{7 zxHn!4a`(ePzP)!(A#-)I;f##b%Q`iSdp3oaSLz02VRn8x0Xeo$J{hbhwFHO#Sk zA8vBP7U~CTDvv z>hI1y+h5P0bb<5#VHrDuKk9ksYaN-fmeH>k&zwxja2kY}};*=Jtto&Nc0owzF^QvhZe<>zY<9Xo8lwrp1k3 z+O<{=FNDNp5Z9Rco<=u^xA5XFK1=8R@4{Fc;LhJ$x*xYYxOW};&aryyM1A_MU*pZb zD|YRR;!<{Ylerr^x}Pt3X#EUV-#vCl=UfvPFyE@fyMbS|=XGMz%PASV6_vg5 zS^xO#k5X@5um?vq#?fWjA70mfec#dRv-f6hjNJNf<0cegg^+>u#Jc(`s>~g1s$KPq z4`ymr}XIZFt^wc}A?#P`NI)BR4J1+})uI|X_#7wo}dUNWXvpYP?LmBI*-dWM%sSjm* zdFq{$Ld6$s^fZ*Tr(Azm(DpQ9*)Vm>1-9?rn*ulH46Dh;scr^R{(_UTDBjcy_;%BV z&L!r}fyMFb2H}_yhspvU_ycAtBZ7FzS)y%ba;#k-<9^LnJexb77m!~ z@r~5B8UK%VlZktq8_WJQ^)7qYLJkZ!Zo$zMx^Yc5dN{^{D=8^@Gnh+C=VQD~!H#|N zpK(#qXuO|!GmdhMQ)ne!MxZjf8%M{yPVjB+H1NYq#pku;dG=gu>|E@b-EQCo2UgvL zi*PA7i)!nh^VUodmRjG0iyBZtm+%?cDWSihqxQ|o8)>Cnk$w5?^Xxqz zTf=vTaMy{ux@pwl__moF6j1e9)SSH&L!! zTppFQhXlH&`xc_mXq&)g!|%R z^39OG{Eg;Y6h4trzxV?4#6-hOBf}e(VYCNF{Ece<);%&)aD)hw|;Wl;Dk^ z?~{jiQ#Nl&cHY-~cEn>oNLDa&Wc)}aG?Uy8kqV>raK z=m zNc|vc1cxm?_R)eDqc}LjdD`xq1I`uI_+d8%^6F0S4jXq3TW}~^^#?pH&bT>nceZn$ zc31XIf$`@Bhn45_zRcC;b5Up8I=c+ROPUc*GwZ_UsF0oJ3FE&xsy&c2gE{juoLMY5 z>|i);^H3w0u_Fg(Yrn+VT2)UJ`%iI{9L%Wt1q13pEyEhUc;%45&!QGy`!n%BG&}89 zb)q&K|CoAUM|5n_W2a`EbKrZ?mi($cuVel{@ZIRx8TTHzKRUMd?%5b`-`O5*De~-j zDtc;0`aAbP%(JH_x;fQ&XIr#ohG);uqwm}qZK?Ha{;%k4(>QQfbn_u{_WT4d5*BAB zSfipC$J%2~g@$yW7@IRgISTqHM_ zyf!>$oWHVj{Zp1_>J8b*18PS6i%T;yfHkfX5`F(E=J9ki)U>Ey?idS8Y+tyM{P>yf zYiKC!`){+s3_xOk@p=_E6(5wo=s_7B!+LOIT8$@fQX1~!xXJVwc^yN#HwDk{@!@Sy zyt4Jq8_@-?N9PR-MSRw7=T7=r&$0W=JWmQPhBBOuMX-2>U4H(ymlqs$B%Q0+@%gKV&LmjtneJ>J? zelu!VPJh+1fqWd@SC2cKQ_-QHKrkFc~)Avg*rV|(1lkHj@yL=0?H%z#EaIs8RaWD^gf|ZR>-g^gXf)eiMImq73N)>%zplBZ&W%~T zMVeGHr@DH&KiJr@X6@R}HEUKDUpmJh53F8MTskp?8Y;&Bx)!f!o;+o0bK}(U{>c-; zGb}{+!%@$Y&gRu?>zB=4-Ll5GY~ieBRpEu7tG#T|tYx)x7tN}xs$E!7a!yrvZbhja z2hjZlDc>i<%2!)jHDRx z(pB=glCQ!l9VIuAU+L1PD;`a;?zjgq=%8xrerPs|LC|u;SN6D%BRen&)sdQC3svP*( zCx!TozxP3(?~n8S4$g%bHVhk%VgZTg!Y5Id7+=95WR}8bJj&y1jRa9fQKGc??i1ro zmO_*#Ryu2dmCny-G7`q@XBp6b`dEI7IO=;R64{{3GmlI|yjKK2kvz+c`st5{qx>{D zZVha>FdS*HxH}-jxKF}e1;@DOiNP&#+~s)Abm_kW$G9^gPg@yx;aTFc-WivEAspkf zEz@UQ9$}Lb**pn+#--1EGR`VE66J|k!%@$l;AjT^7;KWs@@+5E|&b4;46FnsmYuMu9Y%1 zXR(dx&^G$)Z?sK~Y2+zV;|c4C^7PlhQT}`6!BPGpxEeUx+y}?@M*J}xi892MaEyB~ zBC7s1?<{uGCZh*i234qNCaw%{nw z@*q)Ok*crxU{F7OmOJGyg+25s&)*BZQ1ZW|*-890$)~UlEF3WY1TF+%n<1aS$*Ia} z76m}mPdpkvWg3B*1o=(C9AC)a08AoZk+Q!M3^QmL^i|*aA~2&+emxw=GU~YnPVsLA zR^|2}Fp2WS0XWLD|0?;tz^Xi-2PRRTSm}A4Oc43Rqu{8=rpUgrEs*B`BiO|^+TdPid0mWA9>(PyM4vWu+$AN7tM|1l zA;UNw6b4bAm@?G!Z*a^P`5ZshS|S3R0!JBl`O_xyAAut=E^#Ux`9FbEdF%n^+KBuY z;aFUh|1%urJ#eqUk;o@jdfw1*A25kB#O#}li=#3@UMJK>1on^oz z>Qwaq=eU)~gc&pp`g7oz-y7jn+1>=qypw;M^qKdqaEiYTm_$DDDmWW%D3yT7Csylu zwi%^=1VAUAQ~qXPRY&|yX%gcqN>tA5Z?w%Xed?hj4Hh>58OG)Mh(vi})n_LG^Evh5 z>%ash(&@(&Gw9gBw!%1{kv`>X;kfsqo<=w|2DShkTV&;>2xbI-Kl0OpQ9LcxI1d&gi1E2aQX?$Weo`iu_8S=Y^Kh1b>8-P{& z`6e)lIu)t>a?CM<&e$^+m}#+o=~KR3`qWtoMCA`phr&FkfoEyIArVw-T-f&W5`Q zjzm7OT918~Oc43RD!)GjR&&a3V5UQvr{PpuY}?BI-vDR8QSJ~NiSoqc*>EqwO_VrI zt4CthW^yz>F?BNT1sWegL8{Cxgv_9`&VeV=V;|?Z#JHEhk!X)16_;|1OJCLT4Z!~n z$GD@BF53|CB4E`H8_!}7>z+F4PlNNoRlq5GYJf?J>?s7Fap`l7#kk*sQ{}*UpOh#r z+YsZ@pA5&iY{MKwX#d&TtzL%eJf{G0m`$cddsKU1o=D^qt9k!2GC_%K)AJR83~if5 zVG!ksRlE8unIQ6szXV77_rQ_JC+2uUzPr8oCI5Z+Y78kuMpRxn=BRqCCKHs%W*_)w z(5XkJMVs@a&vZw^krKt#%airNxPIv~E*)vGxGY=7g&D$Uya{lm!Q%eET<7R*Z!B!1 z&C}u3cv1yS8qDTNkYU_PI8q{c^30&~Or^zfg_KBMuSYeXvOkgjC**beRlDL^o0P~N zjvFi!`fRS0Vf#{TcoZ-xQCxja%ljJ&c1aEFy%9m5%wRZI~Mpe61M|CAu+%AKP>UT056pI=fM9d@ikm9fS4}v z0{AxElfY`cI-tqmksvkx>urPbP;IcBNQv^I%hP_!vyYM}Ppr}{B@;wGG2_y<$#5j{ zi4|WTSNWWz>?{X1gU(#9`p8P~R2kktVGwl^t99wOfoUW8-+`-zqYbaak;o@zJ(B+~ zD1Rlt5?GCQ8-YobSEOvC4Q9}>r4pF&m%x!IPaJ@w{&jGqM0!fVrylx@Lp?XavFsT4 zr*I_3C01*Or+{f5`A@^C{_LC9Boa$>Y1Cz*Cr1HYLU>y3S|63WxGlNci_9^OQ zy^;8gSgrTYR_}UWYeyXFVf~U4+13L-)207;ILePg;n1i2`M|1ea317bV#8gn$t(w6 zA^Fb$<4?rh3!v)a1K_Vn8Sdpt)KAQ@j5@i0XPFZ}08F9`F~=!{+~0xO<|*@mCPN&S{7<8?DH~=0t8!S$MhK!#Vy;uE=ldF;n0<--uGIJ*_GVxb z<0{hokr{OQ5%+f!1xpL8vxjrgq>u9m@dyx)co>8jZe(#p!{PRpP2mr!`t}>SXGtlfA2Y?j-Els z;i#CDhjG+V2OLJ!F);@iYfw;9R4j5BW(H<*emQf1(Wp@AhDAwND=KcGms^=!fZeM3(1RW}rP;>%;kg;b?xe9vr{)$L**^WGGaY8tcIHB1D$C zoEjpv$%r~nP6IPg*HEZ!IiJwa6fruQeW5XSB>z0$qW`p{+(t%*qpgec0LyYeW6E+z zIuEyfq;vR@<}tQ)T;toEea3aPA~LXUi-7YStJ;yaeA$ztL{WGOs+P{SwBJGn z4FA7;qKdAbOm9MDecpq3H6rV?6;bc2{0PiYsBU&2*X<4W3q96M@otFRB5%XBU7XvuW-bhLE$wY7Ff6ArUn zShVF}M{j#edq?Y{Oy?23@t4#)3aqKUqpP=z)k0l+ZCzZAdpdd-;kVcqbS;EMSEfMu z5lZK6GoF$hXkA!n?QD^rzVrE6j9dtS~-`E&<(DfTS0$I@1mZON{hunM_b=O z`(Pm})C9lr--Ete)VFA`WkFXr#%=*adMe704Py=4G6UVkyFIdX;JZLI1B;e{p_Vqx zCk5vOQ_BJt98A)DU3{qca38WR_xBMBES44zD2#6fjdT6bK8hZS+=Kjs3kMh(%-ja#IbS|lZLwbi4)NfI^csf9lWi;I@mWyG@yt6LOYD>)j|sfIyf^IsxX%no?~Tv4Ga!; z6{sZZz)^@XjG;Qeqh+Au_5x;lv~fqo?!JXB-Pp21W8yGF91)J>kF|rpoXOxFgPD#V zw^y`vcC_6#XeS;&)#Jd})z@2i$H}u8Y{g+4^Y&qbG~WtU@RPGY9=FuzYLjQky6WF1 zf!8jxVR?3Lji~wvZlpr?@S0bg({8S4_Tc1Z-q0U$>8`zFLF=M!*bUk?$<;jDz`4zGE(SUl;z-&t(6VR{A6*^TlX@2| z!0Fba0pxK&S)8})xiX7-|1YIjOIb-!2X5!cOBUl?%}x-m3T94s`$LaCcsq-%(*<2a z9qlaxd1rFYB3q%OTi|cy9MJ>4TfG>LYrGG=ejLjgM*7YT1GqxT!KFk1RG9h1DOu9duBaxs&iJH zxBZ_HI?{^s%&}Vj*`Xua^W45?VGrA;=SYSeAeq4hBc7FEao%-DZqQ~og)Rb{Ovez; zOWRv{{yKjUJM2J5ck2YIMO@Mpusv)Qdcjh_w!mdg0V{e$qw>P0z|zAmZE`klq#ky0 zlUtr`mf-THfCYEG>;=vU%l&msfrZ?F5f{2~S8&Vx8TLRQ`-T^u6DLe8XqUY~o9#E}Vb$lUtf?mO|G*1fDbv&^1^harEWEHO>`8S>{U@AJJiS?OZ2*^fGO8lq$wNGn&w^Y z6yf@4_JRMxtrXNju8@wt_QKx6tE2*cq*ihvRKP%5Pz(;A6U}AN2&Io~!3t#0Ge_`n zq~)%>UJ#8`{s_xiKL2`X1Sdx|%3U@U@W9oW3#X%5xO0OMjO?{h0TXuEQA}7FUOLy{vX@Z>mdRf4FQf`AXKi@Gkbfyv!0@nZB)OO>#?)O-9m$ZjbQe@Pqk@-I zxyAknQs|;;1e?Pyt46XzRl*Ca5lmU@;L>UY%iP7)kqlaUd3iO0g}=bcEzBMy?Io6* zAr5bvyz8sOZ8!!-IshH!Ob+($gou|{xfpVCC#`HP1HnVQ#YL?MJ@I$~ko_ zFZwboD974nFQ@K9 ziD+>y14=|gLH^Dlzck46>6~0hxF^YM{;pgGl!)#L^6v}s?+^0#2Kf&L`40v8`-1#O zg8cnK{-Z(u<3XNJ6Xil8`cy6hO1LL6b5bJuOfKV=KN#fsbU-d7vTsv*Es=ebNAnNo zj6sR$ks$wQkpIshzcI*vDadaM@?Qz^n}htRc$nOpE zzYp@S1o?eI{?#DAKgj<%$R7yue+%*lgZw{(ynD1Ht0kh6IGX_^vTt8|H4z;fEZ4V< zbomLv^70_hr_*yG5mf|veM?FGrGn-9q@XV6TXDINh+Y@u#|C-6b(9N`Xhg8W%Q z{_G&nC+u?}5uF?4Yl8fFL7s1}=RzXCJJ9}ox+E78P;5Z|*esUvNtj$ff8{cugnLRQ zC*cRoav8UrPaNh#!aXfz^L!dM7x1&}xeO@bp8Cm2iR{y*UQ4(qGVSt;Tn3bIPfq5f zgnP2n=11o;&R(Aq^Kv5l1f}Lr4ea^UP%b3glU6p*r@(Rn<0+Q`CEU~1IVq8SL&0ka z_cpy<{)SuzlyFZj=Om23T*fUQ7v!sg{8>T1I>?_L@?Xr50`=0YO-mNpPQC~*^F zC9aq1CC`yriR&fy2#-RXSu62tOZEzg<#`3b%QoYlxLmf8H4dm+Sk@K$?QH{>Osl-wE>12KncM{3}8JV30qd#P=a*{z_bLo{2mI%}$Q02SNVl$g}@XM6AU1@b8i5 zSm<;4p@{D(F@KHA-x-~d07&5aP7m^D2l)$;=k|XIu@Y~yGzQDB4f6Am=Pb!_R*CEB z#liBsgZw9h{O5!Ge+Bt%$nz-5Gu2AGE%?h|`Ab3mZ$Un0V@crlS0K;*m0XGI`A zl;iJ)RN_~s8j&A^{2$!%_v3e*z5NuIzc+d(@*3!43G%a$)}h@i@#}OS43@7B@@s?q zH;`{cd0v@R;#Z8GLOu=daQXY9J;-y;sd4#_L?z}Fmg`R<&-(txEx$iHGg!`dt~Aj8 zmLQ)&o@a>{B39yU+V=;`??aycuXf8n9<2|Se;axB|DA68KM}ncEZ-mGk29y-tk3B| z{ygNly*v}E#Qlru!Sas0<^LAFFIfIy-tx~x-wBrgCU5zJQTcILkp$LfJo1f5=eY6k z@6nrs<+Fo)dyroo--U$FdRLH^+&|2Xp8KAwqIMw_A^2g_eUp7YCvZhO8GC2&c_x;8oc&CwWhiN*Rg zAYYC2y>9u}qU(d@ZOC){@=UT4zqa}AVEKoUXMLu-<=>3f2Ft&SJpJ=HSQ!mR+mUB| z=(936Z~J@e5;@2Fsg+{JbDP5ajQXJnL8)?TsGH%l|(5Z{*oNyb`O7UWtB*Jh#8!<@ZGg z#U5F=y~mCs`M~;Kg8VSj?_pl7#M#=_!SY*!e1DLCSCGFi$gd6Z8<6L=aNU*B{^%!? z=P;>^{v4I!L}CW`J+8eEM5iE6`)0TNZ_zoD_v8IwbP4j@#7?*TpV4))+_y&*cS^p- zEiZ}hLZ0o#E5l0MFIz3kc_mnh`(;*yj6azB5T z$JLVe+jnBzjC?K1`tz5H_*UdK(564gFG8O6^ZRdQyc&6KKefsz6+enR$6u4npBg`# zmmd@V4S8ys% zr{m3H&pMxszaIGmY<+^&+=O#@c8p0@;FpuT|OVl*G|2Q2Z3E}QSM8>@cS`& znlNi{*cWJ_!QsysX3P2q*YHhMR~sLP)kiFHYo~L3y@e+aO_}_M1>Kiws5icDci*eY zmgJr~jGRR-@4tTQ>FB{1ggLkQPWwCWaL>%mpO2?mdZPXw_sDRjQ{E@*ThKxaw?0;k zneM*U_7=Qm)`B-T{1U42HEHX@wy3M4qr*R?lP%kgZ^ftc%fKZ~9gFb`^<9~+*6yx5 zJEH#nmex$BwXM^X>RKQYYLladeR$JoU_ndYf(22_5WdSC9Pp0|xAhLGnQH*P2#3eD zxi-Gj)50cmxoiWvT(+J0^{GB^dHDC7d1mg>N>q6e4>YzcX?NxNeX~=-x2En%O1C2R zCf@_dDXa*)!gmwiQp@FX#(Yb{msf{W>^k)!pzP-GOHgcVwx%3QuBKT9?%~8_@l_~u zy?sk^qbc{^1m2&(I~07DCtF0H{G`BzO9t>VV#KD0Z+!u*rLD&lF%N{gCs**^KpS4l z$c+w`?Cn@W5AfAD=pHv7;Pcb113gh!n;VLYyB3%t9huJg0~mj8cvCK~nfwkGVX(LL z-(d>4eUgtnyG1?yuFAb^d%SVC*z9cuo+W*4~D#{;H$55?pyl}Ajo z{f83KVE+In1-q$urUFl|w|4cq=jQlqUamJdWci#))-8p+2Ya$hSe?8jEok7ygIyOz zToOKUn(G|1dQ`!!zR*H0aBtrgTG-#$-PLx7sb%(UJ`M=JvzM)=8zHW){=wCe7O*i2 zm(oXBTRJ=V5LRpdAZ)wwTtT#WR^LG8Dn21H4Wkw_aJNW9U74(6it)t(vko+qea1%~ zgLM-bo4vrYY~{H@1(v(ABP`374Sm}OUkk3>8f3kMYq3TJt6>eYUV^&tFp-^(d!r@o zn9~>bwG8%lEm(lJ;at80jhj)+6knc3PlrM(>!*kELvrEUJm&F!Df&DJE?9#bxO z3O8Fq>h7Pc&5hDd>=ypOleHAz-ZHDQeD2xWtW4vayzmAL=o>Nvi`p{L)VAKM=C>^B z#{)9KFwzHX{eYZ(!*slTID-$qSmDNA_bg0Xr#}?yV~1KcuL3I4m=zk)m>Z$*Gv<4c zXLfT9liTr~M_HaNL{E9o=<*ov#6G;doatYZ>k^hf%+!g8nPwmA&DBF+-|1VF>0e|I zUhtZG#5b>AS((rE<}EP~C}nllq>#>y!Lzw?Dm2*L(b3QXva{h&Ouz zqC$4kS0P&+3VBCq`o>J=9_aOF1mV-W*|MxMkEVIg_GXvr*{18J+);ky<#|W`Y-!d9 zrK3X6>uUWDd-E}GLHJ~D{zAA99>>L-DBT^HU)*mUm?waBn4@*@Mql1yPW^l@vw-Rz zy3I4@K_`0-wg8 z<3x()Rl#+#eQGyvDf>0=;GMUWWrK%w{c<^T#Nxb@kd~H3a_Dba*plsi_0ZSf(c3bB zy$vVNOFF^*OK^Jc&sej@tdN|(@Z8UzG|lgBZM)6==zv>&f6r|!w-_h*?NMjP5PGqG zeiyn?4gxJxJ6hobR{?&nc0T(T@qNA9qyG7~wJ)e|8SHGG=({lcXz3B34|Xdy50)O? zm}}LieO+m`=3#<7^Xs?E{6+vv^8_rvqq7Tyqk2r$6_~KbOkRC5OE!>DC!Oo10w;=e7~w zi!5w)*i*PUv%-(w=8imQ*q()%1p}=;9TA$J?VLe6pVz_d9Yf~o!o5ow9-y4PzC7vA zjp#uYQ;+b0-0UK{$bVM1z|*p>$y)onFezicTiAjfa^}JT%s~Cv9r0SP`*NB0MdD}i zAt8Ro1MlJJ(^R}SMW*fbhH2s0t`&`<*9x0!KAyYq7nEuW-dY$leqRH0nd0&+}nIZm(PkH|-CEuHolcIB} zwiVZx;s-(*V%+J_)kAG~PdA18nlwubBXRfRsI#1_5199_xUTqT_&{*m1)Ul>DLR+M zKj){vXPi3LGw*+sxh~#sCey$3$uGqbsu8JEBPT__P;@?Rcd0P@-1Q6WsW*#$Ez)a* zsq=e&`ea|xP^#2vz|FN`4k0puD=hF z+ysr|Fy4s|gaJhA)W}KE?-e}_`!qQIB|Z@DL!^CLI4L^&G2Vp_gpVT9h8j7!3m*tI zi17;!qfaBD4K;F7^jdKIB0dn-A<~8#IVn2#+4xuZK==|OZK#oxqH`R^yYYdr8Id;B z$Vt%~!11r~f$&X4+E61WMV}0g+1LnABGQH$IVpN0IQ|Vj5Vj%GrcpR4dK2>T9(*7? zgGd`{HAnZV-4K;F7^cmpzxA;KVg-9D} zz4$=j)2FndMox-82l@E-v_OB04K;F7^ts5#uh0VXgV<0bCq%lamgzVzC3oTj z0beIXDJ-Ox5=P>FmyJ5hohCZ_daPkCi}&FJ!TBt39AV$5j&~+*JISk-xHnVy&5q-fDeRih_t6hPKsUwj{k}e1eT!< zHF8q)TCi>lhdynnk#$?@X!AFGAkZ~!sF9PR1M}wO)Cp9izqmpK_I;so>&79z8!g51 z@rWrf!$pW>mYX76j+E=B{vM=nGR%I}HlHOrHL|w(T+w;RV83dcyKxAg)X3WAx6uxI z2I&|?ZS!8ysgbqKSwG!Ix4oSZ5ZpFmA+-w-Q#3@VLnJfnwim#5m>@dqJJ~R|C+1Fp zFcpzysgaYSyY1Q!0ihX@Hq^*@V_3%jwPM3HCCnw)2(z544{X>D3q)u8bP4|yX}2)f`F`Otq;B6w zS=xL|^yiR%LYVb^P&keBVPS6H24QY@voQVKVz^b9>v!iBSl4p!U7~YdxnG#;{Iu{_ zk$%>2EjX4}F1{=}HF8q)ABfKSbDYEp-{wz=PK}%t-T9P0;x^>qf4VjSGq`;R%)aBCo&vM)T)%+J!LDDxJdUxAXv1}WN|<$V?E}3G?D|FQ z4~k71X(`IHEc=V+h-7Z-X~JxSxro%ct{&k*r2R&Jw=nzeZeiAIweSX{4;p4$$2`Cx za2fqmBPT_FO!V&{orD-4>+Od{r$$bS-T;o}k660ChEHnbr0A24&5yxcFEz5-{6=)P zQzK$5ujcSDLwjoEr09I`m-^XA`E0Fn6Kr%$@|hv()W|v}**7r@A(WD3e`j9jy^Fvp z4ibcEh-BKf315cdcM8+ry}~ac-6;G=qz8ogX3b1t_U$agZXCjYC$u5aS0XJ(jFY~e z?-iXIIVn1dWo=f84K=dba7?S8HDW`JtTtn4Bdi-qdHzDQpL7OV1ZhryuZK-N3i$?(v+`a>y8aXLC-?GxO z+^=FTMBp>3)Txn^qVrid>Ib2_@xYEiC__x0?6ssYb=RIUW>73UW?X+s*~@8H>HF|n zVI=;X6FSSiLv*gQSD3zU7v}oiehquttP`Dw$iE9uM%~@HC~V#Yo+tVOq;9N=ew*mD zxkH%aXsOZPC;UOAD~$dz;WbDv%|m)y9n(_@QRUOf_w!A72D>UDU|hzXwELkCbgk8@3y#C*>OGI)>?vIyJJ^xt2Dv zFYs??(1sdW>s)7S_;ws^sFBrX5^bc;mxv8Dvewy+rDq@_lp*T8G#;E9?KS!(Gr02* zFw41l2Fx*YDax&EoJ zqfIl?YlOLP&J$jU^qt7l=5}zu@M5HcMt5_F*xV)hEUd@v*L+wXVY%qk$Vt)f6P9+`7W62qDEGmI%DI; z6>O-H)#g@gD$BMbZ54hO(n%~U`^A9h)W}-Tdqn?Nr2PAp^z%cc4J<3K5`Ro|YUHHo zla2q+i48Tf`fsGosSpr`#img>DS8v~+EzQnh8kJ7vDw({6&q?~wfVc~5&Con?Rheb zkVKx_MU9*keYEIRNcoNrZK{!8C_D-2WZ|oj-YneC6uxvma0p)4Wb)73rpVx`~jYzK-=5dC3+LLb;Zb#ZG%(8vL zTajjj*#?{o^!(}`(W#O3{K}o{!v890j9k}$ARUXSWj`r8HL{jnD?07dh@20r$*L#z99O`NEum{ z=b?3AE&H12)W}-)ucFg_5?Jrux${`~p+?qw6mEZ)^Cj+3)P`^&BK=b%Cq;Mt{swPzsn}2>Cq=IS z$MRyS>v#B}=FZtfzY2N!-;LDuBls5ZY|+VXZh_A8g$~il-NL^`>iQ8j+{TZJz82{x zgolxS+VEOo&H)b#e-WvhZ{de+%e=PjCd2ICm?z^1&mq!=8aXLC>qLD3scS17I~ZKs zc6w%+)a$%>6_aUpXL3#dcvL>IVt)@w1a*N(kX`DV)#1Y*+{tyalhC_ zjXVk;2*qrR8%x;9*xoIODeiCxZv23`Eu06ab6eI5f4M}if1z_dUorYOg;|&182z8Z ztS^75g+4DrdVw&{op~RJI)CY;L-;zZs{xTZeco#L!@{i38l!I%rtN%FhuejhAk7&4 z-G<$97VEkf+P@ebQnv3tEIKu^_T9%sUx##q@K=$h5o6vQL*TT?ZAl9!Mc*m<9GF#u zV}4nOuosc`)W}KE4~ouXR}DDk$p`{(1-dpAPKwUeP@jPG5@9}9;jUSr^BVl^qI18j zMbvZVC8AR!>p3mQzn%}Q5F2V_JyuRKHmk*k8d+_)zo;L+8_arABdg71+HhbXyh&`R zk&~idFZ$<^&JpGqc)M^HiZ`N+`dJ`4HM05{6rF!3^WDOCBW*He9}=A!S<5~uI^SI{ zrM=8!<>1uoy>^-~68}65bj~YjMB0$KPsTiHM5scfPK}%t{V@M;F#f>|nEs*^IO|{7 z`L8wpp=bSzewcquz|>s*IT<53|KO~DVdtNN4Z+nPde*<_hxtz%|6m5^KW+RAJO6dY zKlH4B(W_COb0e=o+aJ5@!)^SGjZ28CB3eUIV0gn3)u&1vwn23ieb%n1j9dHSJ7PKwSsBChu~ zzZDy5Z!tARTjlM^i_5YnP%U&ux1?iQ-T<6Wg3z#D6v8GpaYGggu z+#&j}k#el-@xmRWu`Sfddc0s;sSWo}ZZ9>m+I(H~ZAiZ<{0pRy3v(NtAGRlkgj+8U z;0UhH_FPMtZLMR*j)7*DIotQ|B4OITOBhLXmoVGk)fx8e7q<_Bxz2TBvkdid=j718 z4DAb|lfNd+`tlgh_40m*`wkAwWBo+YuR_W^ZMfbmh3TKmsIv`P#V70T<_hSvSuXkq zkiK7-I`b_1Iiw#F-hgzKFs~cZi2D8Dr$nbl*6#IWugik+m$RLS3&ruY(QS>PFE! zkxr(czu*I5j_B0LdVgk~v2Vn(m^Z)>=8N7aoD{uZbgruj%k2HL&9d4|`hV?lK zk^Wis60vDS%6`%N$;{J+8d>j+yjgU%<@Lh!*(JOJX}4iFKfuqE&^{~rqe!_8^iOSz z@D8N3qh1D|PYH9oo)zZ0b{ZZFj;BIIcma`RsgaYSr@`?wZ}TdcHq^*T(W}96legiV zLK|x2r06GLF?H6Vl=hwYKp2gf!hxNd8_!^dG$M7*18$tW+55+^b2>G0Qgmk{BsFCNdUsfMW;sA4v7slveqFD)_b9D-@&@5k+lw^!K?#s_wlwD`8uR$ z3BM7ko6n(>tLbw;J`i}BM0;vvJxd?fSXrg&-13MMJKy{=YbL7ZHV+qjhqzS_WRvpLycUh z-&crD8Yx-(eWY!4$D;{;8`-ZZFaxFx$1GPb%xyeZcskOH4ZCebS?X?ond!I7wH0(~ z>18M8P4zFw?68bZTVvp9X6k-0>9KNR6yE?z=hYY=1YG z3d1Zr&XeHOL@NF_y~wA6-Pmh)vKu#gj6M-k3OgUi0JoXU;Kn?d<=p%RPJ@r=2Rl&K z4|gVnHz20KSwG+!Xxx74WR}tTuwPS?yyn&mW_TSU_4ARQY1q|=C;JFhqEjO$MYsM( z(*~0YH8&@4f>I0ok=eFxLZ;vT2q91BxJNy+jQVm{reF3H|_bcjL zPulP~hJjK14!^xDlj1}xL7&ZbIvZd0$k_8>g5c^VI`dlA)on5rTo)jwz_fKbCOp^Y z)WPf*2Hh@KPaKH80Bs&(iU%bG=9O73^21179pwD*ZK6{n>)gWi>in}1L5O{WZHHnJP#pt^^|S-u-H%| z>$cc>epzg&k@M=gz_*EO&qiNQa#D1T4}DJKB{1tljjYdUusNvnUI@p$+9!~wPK~Vg z93s?t?}1<0l6idQT&n%<&Yz)EbLY=8uF}S4mXxJN*0E7dn_u7q;hkbbjjZ=1YmnD_ zQ1^=sHL|u(t+9DTY^agdrq0+rAvV;=YQu4;>v~>nsFBqM(?r(hfY?wYs||N!ZQHUE z-)_{%+O`#<*C1^)_G3k-MppZ?MSmyKCfdu`zE*TJFn{}CH%Wc4%0*!)gxsFBrXuCYnTK1GeJ zHuH?l8Dc|?tTye&<|477Mpm0nV{^6GP$R3&T+wes+HLIb6rCDb?fZ?*ePTn6tTwAf z--0wld)XJhB04p)?h8Y-k@<>c*#6YWI$t51JuZ}jQ&Xt;pvMcRPxYER?*em9u0~9O zc{;~Dc`VXe;fs-uL3Hyr$39uEDJl$?ljRs!Mm~fO1g=--eCD-2*ML*gsK|GJVA|e= zNS)sutrl(ve@&RapAhCcd2UR5*5!x7tfQL`p|dPci)q8{SSWlu(uHEre(V!ogmgf4 z*t|!0Ia0Pu%$vOkA3&r}YUHHo9~1rGkTTNd-;u5r=5}oo<~BWM^#2xq9;v&ph_d7~ zqTbK{F_=E7k@bH5uS9Dr$*L&w#L|`#fBPLZ8!$h&-G$MjjT3xv?+yv z;O={4UDVutZ_y_qulKs$_ouL-M%H`XZY<%Ly9+w|HJ0av+*p!(zZ@Sret_9=#ePjS zQITtHFl}!{q~4Eojxhb*D$Mn?3v>NA6>#>mkfK9%#kmHS<6rK5a zK0Xk1yU1?4I!W^V9WLUiO-D@ef)3$2L^8{{^?^&luFhck{)*Uq6X~$MxFm2v$nC%w#_-%3R0RPm;NzvVy=fN4FACYyVMox-8Bs%@SOZZ8oX~dWhZz3#1 zWZATEQuJ!%<6dv$&L?3*&7Dt*UPGHcZ*xDGeyEX?qJKhkZg(wW%o7-dHHfsQMox2y+P!d(^qTdxh!mfH3`y z!D?vprxM)T7fwNU&r?C?@BMEPo%MZE_$j1YjlKwW>gNN(w0}@|n0|y`LHYw>ZubG< z#mAy;6W))joA4{xfOiY?nEa^lAnZ38{RhIdf7x&;@~j(u^0#fs+`rPo{96w%3RfJ1 z_d|v0zX5sLUx~C!xDV+{;WYewR``oZt5Jsb)zDjnx!#{4QXhi0OZX+EzcTvEhW{XZ z5N%Tnj)&0L2(Kd24>fX9^b@5o*oW?(5^Q*X$sL!4$BPYh_gy*kW^f(+=y~;f#fBPL z&y(LTI-e`!zNhx9MW;qq`-hBu1MT?*E5esVr$$bS{x#7#rk)o5E7HlZ({;TfIyJJc z>(8RIZlyAo$fFFOYS_Ief^DbG1fySSxY6(o!#5g!hj2gAM%J?f6+!3}y-_$R`dy;G zAL(-8c__j>`;^b!xo7ae++UhdUVVN=Y^agd=eI>)hjgnj_phgge~Pr(_}L{oHM06S zR`wU}f5)4B=M>@BBTWmRgY+z6?rY4uF^Tj%qtD=aNBK6nRCH=&?Ykz?HzJ*7>~9dA z8d>e%F8X6g+l7}Q<@E#W!1-ZNnD+`kVD$S9uQB`|hFP9|IA_deedIpC6QWZi>-~YP zqCbUnyD-bnVc9$Vwm&aAHF8q)mqg!-bS~}X`tF~iQzPqj&GGQdx}A)49_?Sl2SQTx zdBS?X?ljS>k+x%5obmN}o#@oaNzu<0eG<}6+RL_IAUZX&ZhM31S0L@CJx_iSt`VIY zSx`OuN^PuR|$m+91jw#%~ zR?=R^Mz!eF$Xe%m(fN0PRvG&nM5jhp`!>wKv*C;HFDl}+;V<+0+ywC0|226kzDC=@FO-DT2X3-7weGd_uaK* zu^B_Q_adOLhE^^%Ymw4F?b#RfNoHR&klD`fMNHu$@2hCuj|#sV>8FKLNFNmDI=OAM zAB)sovxBMc6g`dfm%`Nd2-ClNZUOdJfO!c-KeTc8TEW%e38L44rwVhs-91&pyx!pXR(;5TW`k92N z-_L$tbZTV%ewO22*V_PA`|pcRjjZ{HxbdHBJg=>*Ev1|HHzTh$7l{ouvf8+FX_VzSnJG5p7Gd_wd|{4} zPGR=ppfGLjFno{jy-5E>nEl8+>&Y>4pD@SHzY5dlQ^FiOpEmkBVUDBE868Ek`#a}| z6fR`Bjb|863nOvYt+Zj_exl62RBkkUoG@)q5IzOzDB(0xca0C9HDE5IANm_3+=!Gx z=cUo$)OAksKEZE5*7+3XQnhz}W_kOwkfgxvNVz_8DbjJm)XEU!i_u63?!FLgsFC%V zd@jrL|5hsUd=Ype*ws^*%hdjKaO!$0Vh=ta?CgbEC$*=Y-qSc4oVtOE)E`XSDn#ns zN6t3hk%|whyE^cO3PKVw1x_=Apf;{AZuT16 zE(K;kFsP05KgVmF6ZKf*w!PEqynU0p#c$&bVJ>m~0{w^JR?+FBU6||quy6&^wZh*< zIz^ae-)xv&!gW#SW|N(7aQxvIpYr@F^ptQ?^gEE(vfNIcmzIf6jjZ$13emrSbfw|3 zU|rY8M5jj9b$wd&bx6~Qx~}!2QzPrTzA8Gm{Tqg>!7(Qi1b3Xpc2OfIMXv#?&3D1v zMrvfW0Y>qU`6=W1ZJtY!#2@nh-S~t~jhqynmhl39`emuNduE@hZpTI$bq+2B=fBf4 z>z$hGHSSAfhKmr%EO&`8{WS@*pPPlbPFGLZQy(unnfo*SI9srOUvRnT91mpuzTp2< z|96=BgBe`?!P)wQv-JmO>krP>UvyW0VOM`}!TLiF>+jn9SziaPJMQ#+A(9k!K5A~; zxg#RD{S?eT;nYkU`dB8+x_v^J>w1&$R-~>kU{9W5bPP4;hq~LRc(6lgL!^IdOHPUojN<3`>8~YH^BnqpQ1;~-NYuHFWZlQI4hAyhtXQ{sh-!9PxHKyJjU~8 z^68$3$*=Rgm3)Th?PTsO2s;pCb`HWW#FzsUVGm+_rbGAsW1RMU07*Q~bA+~!t2~#H z&+=SBuJ+9H^OzlrkS3qwxrTh6=Q{HFo*T#)cy1)udTu6jM?siHp5S>7nUfa6JaV1q zPBJG&1fG}2^`3{woOBVEktcaxLFNvJu!_us3BqdfrJmQ48$7QkU*>ru`Hh}8lR0rB z43jxv5w?;!86a#YU+H-VxzY13@)XZ|$lMVS_K~M~K0t2r9AUi2S9#`hGI6tKJ|`1% z!bTWFzS?t|jC%zPe1;~T;hFEV$1^=QkU6O!G?F>lBQ%p|d7edntLHi7>pjmS-{85E zJliwxp~sw@5O`lczRB}4^39%Ckmq<_MdrZ)VKtc(C&F6t+dZ!*&-J{K%!v+RGx=7} z!(>i!2wTbX97fy8t)BU*a|m~1pN22q4CAF_0 z%bY*faE)R9?wHy%8s>LNs=NI{{InarpDf3brH0-37ySXFyD=}vnhn&2-8dJ1(&%n% zi@uXO2Q|VT!}|?K7&~gi?}zmGHO6qY;X1>U4L2K}ZFrvHZo~ZkM%T5REXT@KhWR~? z>gx^jdtudw4R15N!|-my`^Xi(O%56^!`N4y-yw z;W>ue4fh*fYIud=2Mn(@yut8h!%rICZg{8RJ%;xi=JyM_E#>5t9~)x~^Lu~Q>kLme z+-!KZ;dzF6uV2sQ_^g2Pa>J_(uQ9yd@Fv5?=-x}@P5M)j#28r z-0&E~)rRW~Pd40ac(&nrhPw?98D4I9mEkpp*OTR1W|QGz!`lq+Fua>A*FO6UA2eKs zW3SrqZ+a-F4cC&#`hILM++=u`;kkx84QC85GrZF9YQyUcZ#2Bc@K(dm8Qx`hui*oR zOL4xS+f`wBtl=8NlMFW+o?&>7;daCQWVzm4YIud=2Mn(@yn!s&r<)BwX?VNgord?2 z<$89%Vct|wz1;8^!`0-p@Ao>xlMOc;o^5y@d7LlXZFtD=a>J_(uQ9yd@Fv5zp=RYq-I1li^w9vwYdPhC2;s3@&VsK=SIU@ z3~x33oZ(%D_ZmK6xD@wn)PIHHv4(35PcqzSc!uFQhTF+!`}+4AUTS!S;Rg(_HN3&_ zX2VY!-fnoO;XQ`;8|IgDTDNk;V+>att}{H@aI@jrbIhF}&XJ zCd0#qw;A3+KG)Y_x8Z$;50Y!VO&P8Ul=*ial+%W54L6X_^JSY1&oVsMaHrvn;bn$b z8eVO9o#Bm!w;0}P_&LM74DU63z;G$9Idoep439NjV|bF`M#D46=leF9W4PULzu~2Z zSCB98WgjrS*6;?yn+-o{c)Q`9`QVJ&lp7vH9`DOm8?G}v*>JPr+2jen z>^#HWhKCF%9MihRbk0r#k;WgL2w%t>Fg4 zO@?O~o@=<%aK`X5!z&H1HoT5J(bsvS;Vp)@8h+03E^@suyVvjm!=_`!?olqynTb=Cd0D~&o$ghmizx1!^;e>G`!mII>Q?c zZz0R~2wM$5XLy(4z2rt;{{x0gab2r=h2gP=YYa~^+-P`);W>ue4fh*fYIp^Cim%%P zhSwV2V0bfms<(gA@OHyH4ev3$-!Q*qRzKy2#~7|QTt}Yf*E`v8v*Fo>=NaxcJY;ye z;Z=s$7+!C9li^{*+sIA6ZaWO`HoVX9LBnOZ$Dn2T+vobdQrd8>;ReG^hG!X`Yq-;J z#_%%3D-EwEzu9lgI>Q?cZy~?M+iW%boZ(&MW^c3C@Bzc6xUZl#6^6$et|3qNekK`i zG(5xb9P-uPzTI%Y;iZOG7=FO;TEiO*Z#Mj-;q8WZ8s1}gzhOQIsP!y2JjQUf;X1>U z4L2K}ZFrvHZo@-{mm6MXc#YxphBp}=HoVR74#T?*?=yVRa2f9FXglzCzLnF4YYjIT zZZbT}@La>4hBJnj8D434wc&M!HyYkzc&p*(4DTXeBjexj0mG%ZAEP!EhR2d;__8&I zCmC)uJcB&b+s`rFZn)p@Qo}0@KVW#R;SGj28-CL8cEdXj?=igJFdxLxI+q(BW4PLI zo#Dxbn+?x4JkM~q;UUAz4X-l1#_)RbwZ3gP86Gyg&F~JxyAAI%e9&+i?v1Jcl;O1D zTEh*7n+(q~JlAli;f&#B!)tu(ya@H)dA4R0~Ll|0M)dCu@I!+Q-MFkG6>m8~GZ z)%zK1xW@1#!;OY#7@kAEK60VmaKGWDhF2JVfP6#b!dk-{3~x64q~Yy`campEF6=S9 z-*AL`lWJ2=zR}x{FJPr*@owl zTfKd^;UUAz4X-l1hTQJUt|u?_youc9x!6yf>O?UjzVdZplBAlH3S5P>7`whA?d~tq z?mvsPd%8%wKNM+q5;nG&?HymFU2~CkZAIGgRZ09mYQOOvpT6 z#ntcJBJHLZY1dYy-LfL>K3Sw4e;=%v{@7Kd-9L)7J3Ud{dM_{1uC+)zzKdVX_I|lY zyBCVII|&n4G3%XJq}?q=+P$ktyMHUv&OOUj#D4zsBK`fnNV_wRDX#r4E7I=fBJCCx zX?K5-c3&yd?x#iCxo5{>s7io8Mk#=_!Y4@oj z?Y>^5-7ku?bI-sP(S8^3*|8$*ZYt95o+9lYD$?$$BJK7TX?F&n5i4SQuPM?lQ>5Mf zMcO@9q}|VtV#jS{ctPxN`sqS=ove1hfgPrz=xBC-EU;d=72^EkG|h#*up>A6Y*hZR z|DBb3tgsy#m%$`@{iyu@cmUefh#J)27}!~V>*22(M)bD;srs89_}hhLyjP$>{qY$; z>o4{Bh__ChzfPp;uP^X-5X(+dXJW_fI|F|W@Q1G>oxgXA9k=&GfxmLpe=2khTE7*6 zzgh67+sjnz_r<^;-&Z;vQG@#15ct~yf3>h<`}G=sPY3?Gah-NU0e{;9e|sK5e`4^^ zU%&D9THtS(Hd;BcWA>H6-~KQ7-!!AY0kLEIjXp7dyzGa+(+bq@MA&iL8xa|raYLpN z+d_XCK(OAq zU-rN8!}Y!!_S(*m1pb!ed~ga^BtiXsHt<*eUzjhX-`)#b_4ob2-&RasyjP_`{e3&| z*Z)}Lep8+GyUX}<&yymL&2*vS1mC}sb?YVnD)6`RtGRjO9xT`TorFn()lq*n@HewS z{Z4=#%QPY~Y=l4E-uEG|{w4(ehH$()u7JPu0)MG3{x_1iz3gZ8cYWY*8FsGetbhdC zG0Y77^?$>UPx`wT%hg|R;E&I4FGIg+P=8&4zdi8BckSqp`-%GdP~dL{@^37#y(@F7VgC`n?@ep_Rbu-fWyfC=CbemFAVKRl3U=g1(TBe4 ze_M`IZysW{XG=;+hF|t zoALKd;BO3`S1aW2hk?KHALi=!8RM@6TV)s$BwI zgZg_{;IA3}x?x0rpF^tkTNn7tz+Y*B?fp#PZxj6SJ#hNNDQMQ;*1+G;>Has*!uowH z@K^B+_5~TwIEBjkdpYn|hLhOq)tT5ayF2jL{-fOf_Ndsg{f@!@#m&>>(Ome`HiMky za|1g*?}Sas1}#$sJ948e8S~@Z`Orpa+RoDhe@o$yziX#K{c(P>{_5b5@2j(&zhwM% z1^(9Hxt}Z5nbgVt|(;BPJb@qKsJ?<>aN!-2m> zJd?ultU>*)3;d1!c@)*bi2gPs)%txe@V5f~xSwfIe@_PfX22h>Rp{?)NY&pffj>S2 zbG#AV7>2R>yFTzYc3k1}x|xB$;a}#?>z*+FmIVGL!C#eDPVAT+ z2>k7aKb_Z}6g#%xCj)@%NnZ_nE-o@Cg1s z8Ti|6{9&rjZtvE>-*))J0&Y^=^Z|<*bkd-QG_I{tm*)CfIO$_aW8o{chlIRxR!uXl2EYuAd0} zZTtg%7wrV^?^WaPrNH0Ldi<6i9Z1mny%6~0ACIqw4ePfbsn*ZE6NJ20X&?NZD887e zztixJ4Y`pbLN)y9{QPI+)!%H`VHH__JotW}f&}$#V<(LH)*DT=@Lu{eiz-@Tc?hLF4apfxpS{m(j|J9kUMw z{wfaT&NtvXTfZL!{x-rN{%3=>-**Ck{qU#tV+Uya{UPwT2hK1AvqAm+Ht@IB_$x8~ zMx)c&o!TG#o43=l-u!x*JrQ>F-N+2WcKFlzkJp)6zl#HZbKq}^FXBG6etb{M`Wu5< z==L6K{M{1xTLXWm6!6D)x~#uu_=DueUzzcDci?Xm{8bh3_wK;oJou{?eFr?Za`{A$9eDG}GZ@t;x6OF&)aIuSQ)?eAB{`d^Z z1+JH&1a`LlhEa;Y-^Ts7!uYER{Oy6i3%v{Xss7Fi{4K?xn+yy3t2F*@3jB>}@a>>3 z)!$nKf1BYCP2l|T_wZ=P_FEkItA@Y1>I|v+yFKu?9sY)~ob}`H!K=T|1^$+e;P0Wp z->O8;-x%ZXr-8qn@b{wv_2WBotV5$Ln}wZBzu$VD@#o%+gN=@tO_$+!?WGJ8-QGii zzoo~-(QYi~_Kr3F&c@(HHtVnEjfLl{H0*5s=3%GR{(Xb-cTM1L9{f#b#UyC`-W>Q_ z1AjxXVg1s^UpMT^pzA5*!|=!YYEZtrNV|V6((Yl{(YLO51JIwhKi031zX`BodCtiUv}6Bj;4;QbVRxL0NcX}H zLpmF@4%5Y-E~vg7b6tt%a_!OtJJzRB7Nzi|5P!dqup)w(c9iP&@$NH(bm$M$+Wh0rUyC}b`54a1^{h~(`~KY z-Rb$QZMVs4TpjHPrY^n)IAW-LeE6?l{6}KqtA~F2bWP&r$B+Nx_g?r#>F|xpI6Qzj|mG2l|uZh4ZT`#--ywFuUgNs;YC=)Yp$nEZuqYuS&jiVboArQ&sni zW$9Ojx8FKk{^HH`7mR!U(9(l7C4a6jIkqMm_wz$lRnfv1OO8D|n)1^_6MuH7YHex! z3;Oz(H2yZqsN)}*aPEKAjC=af(!Dh$U#agK_dkbfN*2yvIA!~xiBBEcb!(dT&p3M? z)KQ;ndfxi|Lzm7!?TTZ^A5-3R%Uipq#6RHj?%FwT?VPgViK=7c`cb7-SH)GwChD(> z>W?j{x+*d5u|xG&mCPxb`qbYW8#60!{QDK-I{nXOBS%12$w60;%{He!W zKlRx9smFb=N>(C%D<9wfy$65#k(ci}{)>OT{r9CmJa*RhO!@wmi>uB#XJu7$<=>mG zo;mg&^wDeF@PCw?`cT=alaH;cJ?GSCj+tLuT@#;i$<*4j%THN&QCxn^)mPPbS5NIe z8*8V{nV2B@-MEPc5-c^Zc-Z6tsgrbHLEYbzkcd5^|i1*7N5@gI5=*I zYbwt_>pc8znfNDM=M^W;9CcnC|A;*Hp8A&ZhAZp8HKwj=xTt`KwoA`C*~*@s0E5WnOHp_&s*I zlGf2rv{pXTdh)E{%wPZbi^Tlavgsf3!?gJ$Jtglb|3}FcqsE`;N9qqt%Ez2ql4>rg zuN+lXS&sIfQ+obc6Q4hnPH(EaIF0;erB1|<%+LP>`HI}~#`=@TJ$op9c12wkOI5W; zRTHkPf4t)E*5m!=&wsq)it?Yv?;bVwn5k>GWBpIFQ5xp9e)rIdkDPkuu~QTAjFNP9 zx@uZHXG8s&QOz+!r!2cWU31C3$DI4=)2IIDvc`+jTV9r&N_h=`=d**mVR zsesNsIfj?G0K1(|EP3W!DgC3jmw?mjJ z%M(>=-}}9BC9R40Z}jrRl9f+P*?(x_{zK)J@t>)Tdkyr*>0LN};)MG833cOf3>d$#wl=eJkjz#3T zLKWg!hzvXz(V%5nAC_gxLm11>L}Z{n8J8W-&vK-=CE@rnq-+P;Y)0gD3CsRQQtG(P z=GIM}*Il(pS)T?lH8P*e;Q0Xg8ahN^Sq)lGyN$eO&GIa#esIg*g`<__xdO}32SXuy z_CZ|Z`{Hac?I$9#9jg#$BQhMV>^Ru4?07`n3Ug)WAZ44<55J?X7XBVmZHJ$M84CGt zfX=!xJ%~vElT5pjahuWk=ifx1CHw_2w~Ooj8kpDhs-gZD_5PoVnN_s67pPTB$6$YMCC0kDyAS7rhn*f4 zvK_?PW09tZJCyUyoZq8vraMdhUp7s)Or~Qf6HRDu&9p`n<_``=69ziETPIM>@794n z+Hep|oG{T^<(g>3e$Kf(>bBUP&K3J#_I0jcu5ztM=k)grkns`vJZFB? zmdf^Eu1pcllr4q6p3u5@uq89p($?3DgD^&cY6F30J4J0c-rD+ldR)OFcMzY@#e=vX zKo~yQQFEF8fxdoDFC&IT-W`8l0#@YNCfux^lM<00sl1lRyTi)zr{#=6iQr5rk@pQI zm-DEd3yJ8=Tn3bg#szsj8}M?%9f5KtiHJwMTu4OcL2JSyZu0*VcZ?3s&K z6VWktF|74&nl86@IOyLVX_)5`JQos?oM4HRh?2R5phWhJ%FBuDkze!Y2KG4MnUILi zGdcRZz_kF6b!_QM^uL}<(2%`v&uy7!i`OBZfn#kY#=})$4O~7$Gf0_#Taa%>p6kQo znzj`f95X>mcI#ko?m<%X(h(n zykPn5LH=KYJpW9fo-5kC_nZlw_bkjT7-;S3Fk8*TNLPp6AL2&#_ANpCbhR0yk&Xs5 z=l!S_R=lV6up)yUnMM6kfB)>ES+`}3zmX3Zx$4^P&}Ke*d+Xt#h{je^w*iBh))pKk zFssk+Xc_3Z9WBt-J2Z3QK-ALGkGo1Nb3N;Y zx&BSUyv`aHX4&rxvn=nWvMlS)??=ciyIYuL`8_{%ZtFPY$qdbiF8ce~H;7J+ zoRq@~uODc?9BCRc9)}Nv`H0lh!b#CPMW=m_;f(N|NS6q+p7#oGMtZ+6+v#J%wE2uM z+w38uSA%0Y+v3i1A~rL9trvPdKk(O$-JgyP#Z2z9pfZ7zv|yRayBwPIj{0vegK=>3QnLZy8=Av&3mm}RT zOdo0X1q`_FOccHfDX+s-=R0s@?mKq~bHDhYa2i~VsQUts|Fow@)_tLdHoTF5(2YnN zYUHHoi$(t$e6xw;I(#7f7?JkW$Vt(e#Oy?by@<4-Mox@X9|%0&I~(Do=;g@kZ-K)_c5Y-_>pTgJVs1DB+bhMB0tC7s)AnLv`e+oU?+V12 z6+x&$q&+oqQgm(`^+u+Mx}UyLbZTVXPl1un$!`DR2Ljj4zm1aJzj$(n!1|?lppX!w zEf{DYW1nSk^`s#Jw^9F&T$(KV9qX)r=Z$ra=>VYtQU9)5BU$RxOfIlq*XB|Ow=Q8e zvDVG`7kx5ysi*TPJlp8=40jtIGQ8aID#L3GuQ$BO@UY=+hIbg=O_ny?XZWCDK8vC@ zJXR}npVctd z+`7NxC+z-?pYW6PBjfq7zvCym`#XNZhy5MDQNGRjUa=ng+~4t&{nRf#`X|4ZMzcn; zTjsr|$I>zc-JDsB-P?=w=k}Q**8ANe{r#y(JD%GWvmG;vwBzxv7=MoxY4^*c*l}G9 zzZN^0z7Fd*wfh}_!~1AIBWkXL{F+nxFy3S?); z^knEP)5r`0e~X{T2>RokqW-1@{+e-aK9>a~X#L(4_~Y-)YyEf!Q2h-A{?@@?q5kdp zf8D(ed=uNv3yBXKqaphQt4C@s3n%bp#i3Vc zT{teV5vptZ!n8;;tlibk6n%Nu$$3=Y)U zbG|ue?$nv3Q!zqEs zYC4Om8Zx-6s?nBmAVp(kU4vZ{tgT#JWmg63mM*p%mRD3%RaJg@M|E(~Vn~C5syb%8 zzH!W$F#{+lt!ub8EOB>Fv==R`U0Sc~l~+{+mm@Ej7dIxm#CD5CQz!;z&8g^;1(k+t zQe-Mai)vQ{7o#ZzD<;cyyGpzaVs+M5)L&P}`gBKG2WTUnY|9l!A@wSk*DYRDfg_9N zGu6$;M7yDC8Eq+n&Ezv|yqdC?*1MHt*Dl4;=5Xo&x5Z+hvN3$<3Kum58yc2YxW{7Y z@+O5ErwRUH0?u>3{@MF1Cpsz+ZLM(zVMY;V z`r$j+^dF4z9mo8-UCtT4PIsPNeEvT|+5ZT617>Ha4P!tZlfu)deD8<6gE3<)F57Eq z^KxK&^jz;cZ*u=^vx^b9zh~Bt%7OT;(n;4ZY!NCdn6&!{GW6Q)1D&Dgg5D8(oy>SE z*zagC`UK_>9cMxd;=R${b!{28`4NK${uVkGKktvxCptJE=62ec z>l8UZ4SDUq?784R%l}~h7oid-Z))P|m|1fZy^VQO?TelKPeLV0ZMHEz`r_i%FJtG$ zNnR@uG{O~}YhsSrsC7v3L#7zFY;Q1}iqYf7gH(T#LSB!N=6m_W3O}?s>+iYX!C(xk z=inKJ`5CQXe%038t=^>RQ8uQTRT#sXocUhA>0O5d$fIcP&&@xG`F;ga-U4TSyzd>i z2@LVQ?KXkL{J(~>-wrK^cUq&&w`p&(7qi%os{FAoBJ&tTp8kt@#B9X>ULKjRTd_sD z$2Gw|@Bw+D_NgZSzXg+aw;l|hamcZPXHIx)PcY?ZFnM3Jebhb?9Be+r1KX52{FdY9 zQ^W^$hVFiA!|}QPqF7sjU(Vz!KmU2GcF6Rg-gv-+D>?8Rm*22-kYt>)W|Pp1#4_FF|ejiL&47Sc*$ z(pFi`WoBDeqtn`&K6sGR+Lk`pbNsH5@9xmNiXqMEhO^H$A7G-+zUa2Sz7wqj&HEVq zY*@1IyO>2hyX7%|ahqkd6r9K(-HdZOf3$A{TCm@l*L2qI^&x)-CK47~(LSJ6eMS1N zK#H%)ZQ%*tqWm?X$qAXU=521NGQ3mVNr%zRS7Pl3=&cIt<*y8R(ca0k_#XmN`CKOIx;y1YQ$9g6HrJ3eZN?68Pf_HtO zwKX%|T|QJpc# zZ=qtCw<$dl^Hs!ZH)63wtO!SBo-U&ZAE0~JNxJ9y#<|hYM9~6Tbk4>uJT*SbmPZNg ze1o9MHkpCk-TO0b^Fmi{nG;<<#?ETQRX4^Q&tTET20EX~pO(s=YZyCM`E_`)p*zG|1H% z7TR+4eCDCZL^{tS9TchMg!x4`_J_0o8PT`Do9CkS*u0}C!YJHHVgvhDJG)1ko$l`E zyECHqT9^86n`C}Sfq$5jpX&R4H&30W+(63|#~j^;nIG?RCnk^ojed&b%YU-_$VIl( zYMMtWiCu%|nYT#IH{vuN=uHl^?)cPiHD6}5v)`Xqa(+>*(PlS7JU%I|ptWsU(t!4Q zV`l%!R`b+wEnCk%X2sSTzMpn`lbhbr|uUFE*p-8xS7eb=qyVgB^|7SsmMcb;)*mi57S^Kr&s zb-CLf->_@C*V+4Td?L}FYQ$n7;jJsW{bP`0$BM2l7?nMzJ2z_AxHGeh;V-Nh zm_NJQo3g+{^Ebca=4Fg`aJYD0Yfnd~H#v8ATft_ea1-|)eZzDTZcPh#(#qq^8{9NK zI1Rl?&Xggsc(C(La;tKv??SgK2haXScm6lJZ|uJ$&b>M;Wen5(Z~4wd0=|@kzB7*c zl27;sC+#ki$=@iO?zo;0@4Me*1Bq~Me{?s#G#TX2c+Yh9OhVt$?Y8(n3cYna6tIlf zE#HSY&9_h4<(!F*Cr_e*B?E={F=TiD%^QXF|dD z(22vQGw`Uu;{f;bhdTGSi%XX@R67jzc&Zvs>zOkG71PR&ohbCBbWs`v6Susr&DJKauC85t;C z0Sn%9m{8$LL~>yjAvNDAyw1TvEWCc`N0)Y_U1qhv5z53TJ*U(ZF7k%%^7Me>Jk%lQ zc&X=vP)P0hvfuSyC^SFf9OJsPEtJhVVHq1|j5F$f^#VSZdmSGPxu4CY#u{az&_7(O zk441&ati-^2fgth|As($|_F$ zU}}>u^~M;-ABFFa0(*93t=L?b)tE9RHn3;StdVwB+Gg8sOeu~jh>r8!h@N)1Bkvu^ z`we3HbN}Vw%<-)Z4Goz;^-CihG|@ovCsE{TGrRk;WI8T;+zmZavnQB4_H-aVW8nRaI4>VZwckxnpuV_9pU}k{31_VU}Ipgb@OJcJu#}y+1ONU756iTt(!F~*?H#Vuy^b^n*;p}r?tf%kyy~W zVf6WV_&#jTI#lPZtdE^PcHy(VK#A8WiAUK}w#BDyu-dz=Cf~@8A?;n(mA|x#{%xhD zS?ym~P5t;O+lIvLLju0knK7AOWE#~O?va1jLT#cd(R}t>%^z7%xhj3sxb_a~V80=2 zUN;?I>i(rMGZX5@+bE)WF3aZxQ#+E{_ds{#Obhqxp%kL5)k#+D8`k06{DhDbeOp?R zC;!9l?2o#=Nkw_4@k+eq`=Hyg25+fH8XVV25L+mbx2a=D^Fa&OH|$&En6^LL?8n{S zCgcPK^d^=0*P*q}+xq^ndbX?W_%N;8iQ1TgBgF%IgZ|yLfk^lkttfGmYW?cR_0-K9k#>Xui$;$oPEgP;T*%_@n!VTyW7)o-H1ZMAQ-aGZB= z-#Ww}T>THLc`4diD9p>r;y|ltoyCuSGtE8Bi#OrjP4(G7 z=!R)0$~dvNbwSiyo4dDfoj%;3Fm0=u89j4g`XlB{oGmYC^}xpo82JN!gO*7mVZJZ?tG zhqrnwCl7S?C7KT~M;(uycoSWOwH*N%xqNLgGKS`t5J2tS%l#)FIoWw4vE|&N*%o#{ zjG;gC4(~ot=&IzTJP`W&ORC&b|TRlh541 zIN@u;ysiCw)4KC(yFYgV(aW8&S&nr_+TiLyY*hN-vf{$!PHePOxB|gI;mYip=%)vw zjOuZN1JR9H?`%GDq_O3uPXjR+QG?Q3Mco)rtEcVksomaa1nL-=J+B*f12HR{q=bT2 z!yeakWQ=WIBl&isV$+XW&BLr^Y2DcCq+10Ajn3eN{PVk=JzLNj$jkdUeJ7Hrbmk-+ z?6CPvGoNvtVb6J^cLWC6644 z*Mp6L_~B{4vfB5XMf)&LbhNSv$2|s@me{|VX=Bpa**F5LsVyh6Po6CJaes3Z%Y!zx zICbVg@3@q2m$V;3huppFm?O9k$125IUJ%1rqt7?bb@g-bV2W$WISe#+n6&?bS@091 zXtrt0TNlH&;8;cN=FF(HF;?>o(|eHT!|y|DE*~^+Y_ae8lNf0pXC^TEo{nfO;~0h z-)jD;ng86$?BAYTz>%iUPcr^i#4pIma`p|kC$xPq*Y}5TtoALY?|0!?vGIOer-AUfemavEQ<%PZqSEEbezJ#+$1PYj9Xl>gMm7YwtR_U|@lNc75s~ z-1%@?wDrS%XU0L?^wNK1H7_%}e&>7q{j1{uzvSySx1fb9&3!JU9_L6)2xpJcU@C2Jers?{o5yG$U}Rr%GRsNKzL;4oI@2uTlqg<*~TjBr|HJKYr#w43;&OXL{#AVKf!IG3aKvSdtXtU;hf`j_WTQ% z<6XF>JZkt3cR7wRZ_j9RkekMK!#HwJ+utx^{&T7pw6@_v43EtxGKM=ZcJFdx(n_u7 z2Mu%t0(%#Zo?vaSh(Mwv%0 zZbRKaynrK$@ofWmp3U3z@1hIYGE+0XJT6{f&`q&gTuDbTSgR|wI3as(Dt_xe~9%NJoVCx z9K#!*hQ3?&$=Ixu=)|-Pj=k$-^Ujlaoj2`QR&$`ceJnb|(;l;m#&*X}>o%%~Tg~6^ zt{!8x-__lY*RD9bo~^f<+q;`zK|d~S&8_Q-4tDzncRl8eo_F=Hn?LUMC3e+27tDM0 zH_gYPaNfL<-xqavBk`uzP*X6S$LJcCDfV#4uzVNd@p6xE;z8epqrTh|zVY`C(nkT^ zwMsIg_gR6~P^Q`c(eRoNlf4b2ev2?R}tUMUeUKnjgG)o$C0W zj$;OIe$6v|b|*&P+Fm<=YtrJ==8bEe=s0_ZhDYKsD%Y`zz2@8T*n?{F zMi)%EJ?{A4w+RG4;^+c!YjCC3cb${hZ3o7inw{{=Lsy~M^tl+@#VjL;Ii*qvb z@4|J@Ho`+!zQ4Q0w|(!q#UJ9&$j4A-xcGkymA4uw|9fuvGXkwfxB?Eoj%9c7tb3A| z`I#}{_s8M?-hdM{5`DJmzGdeaUa{dgCTc$W<&f{?kb4BNmnkqH%DD9T9K^J$u+jCU&$^>N zeU5Ka{}OChVq;nlV59qQ$K|nNy7aGweWr^pxq&}7tvUc_)G!a<*5qrzNh03_W<2KY z4sfc-p8(TQPG);HXb7hEMtJV7@ma^LLdk_|$nEjGM44?*xw*PDcY$`SgQhMLvcN3yyKg zs!dMNbhXlPg4S$Mo7y z19RRl^{0SUSqj0lV_};KrlWl_=Xz59Eiiq`%fKqn)tWw;ZG(ENG+WDd4(gH^g~ zz-Nj6J(@mwsK|F}a&ofBImcGnc@A6%Iqkm4_oG0=! zO&=oHscRa~DbpW5w=M%)*lxncc18PZvE^f<{XN*|C|6F|VZG4~{Ss`nvqgOB--iv; zYM&>yvbmy@}5ISeKPY& z`PJCy`m)3JLp$`=7iz0ZQ_`m)daDDBh#A#|9Z(fEg; ztDgbR0W+;K@OOnj1grM^IauXkI2#Wf(;};D$Xc*ErhLT4pR02VK(+rLf^UJGX>p!A z9qo`+JCD3h(hib$=doW3pK(`1U*-QsaH{A$06tT6o&eL)K6wg!##O)BPI(vP-+@p2 zYngdC%E{_l`a`fvYYUit0^0d4nDMCpBv{?|4`})a!914KkH$H!+LaBaV_Y)NQ`(vZ zRyK=;8FwyNT_0`)?|_W*Oq}}_!W+SqaeEAG!KeM5U|!D|J^+q~Pn|cwbkrfI!>2q3 zf{TQwfK}NG!ARP*a|t8C(Ie9~AS+&Whz$*VwgYzZb7!;8CWq$gBGvPCw!-B(6 zPPXAQpK~=inb!pBSA&(E8n93FZ_)J0%s=gXPt*TCnC+JFp8%_T{syd$DJwif;%0!A zPA2$Xkv|Jod3X+-FE$78WPxK@$jlq{MuU}|3^31q%JVgSvbsLc0x!jW2iqUODsCGX zO~sWz2c~0M`Y@E4{_sBb0jNJol={*y6n*+if0d?BR{gQt!L8UFY-5lyb)DfF+bW+qntTFS z)p;Qm;QGn~(`BCNZ^XttKaDLJ8`C<34X1|7@4%<)%Z?2>?a*g=Xr~ezU0?c?NAo5i z&aK1KSPK%PHdqh{3qE2|*Jb=j3?Y3*#lH40>s{=SyBiUyCpNy^siUMpYDL*#xf4_`GD)wA>@GkJO$#2QKN*IB*U?lr!0NfpPqYAb{F zTrIM+aVgiH1ofp{7p!lnDn%4Pa0!-aRLfv8FNwsCqNSzP%WEr2OH=W~0XgB-Cz-bj zoLW5F>tV-jQGqe%_aYRPbX+e6Bzo^@>3)64^-Q^7B`zQQEVXn|WjI{l(69(+O=Z<8 zE!+@XQ6>8q)t0&{!OClvH{cZcZ!UC+>uHpG^;TC_hS|&Mb^qV5T{*HhaZr@o%j^|J z;oD!`MV<2NnAFeEcOyI|BFx@(ufq$#-T)}7XOufEj&fJU>Q#wyM;rBUZf^h-<&FyW zilW?=hx9N6&s{$(i!wN((d(kzCoMh9(bQfSW#sh+K=`5~BFwvMulql5El+e} zH5cXf0(%8tzcwp-X}#{tYqjS0?gT{{1rcG6Ui7*stn{hZFuQo{^C-tK$3c{1SZ~n` zpRabpXZX^H@GOL*W#ihI9B0VFwh3F3F~V2_pM6D+DJ5Zq_5t|H(cU8}0H5LCM}+?v z5k49b{yZX_pcR<*&O(^|G_`i86S3d@of*jH<3S+_Pdi*YO*zJ25D{J;5ndA!=DQ2! z82@JxVSb;X9QU_JgkOyazY!7sFe2O)5l+-jA=)1i5zdYXbA1!`YY)Iq5{~{A2s0j! za}us!*CEW~`;;3#&)6Ih|CbTr-$sNxBEqjmgx`w@e}pi{AnS1|CE@zWF-7H=uTVrd zmJd1Nxc{7paArh!N<{doi16x&@YaYh-|Z;J^nM!=?uZEgH6r{;MA%~Gile=xh;T+k zxF90DAR^ot5xy-V{NsqQde_4&F#W$o?EfqxJb({q;;8S72xmrwFNp{TBf={q!p#Wt zeC2an67Gk0BV5Sz-1eDeJRG6FDdg)o~WuiOmFn!l0j|MCfi>jHdrF8XzqOP3fuIYBqGy0$lnT$L_wFzPE@ zw`;m&;gZHud5G+l>I(obEM2mwp`x^QMMLjOx2OcJI|zjb6`OvJ!cV5=F%DrU6i7@4W-rfRi`Y1?XI3(QG?@KRl88%6Mo36 zNAu863Lfm`btt?Vz39ylhA3(pODh)D)!=!rR}5M0(n{1yEq+Ac6!BNs2`5~G$GlUM z4$I4f4LC9S+*{gEv$VdkVe!&NK6CQ?!2=`GtzIfw){8XC!y86+R-WP}7d|mE?h^P@gy+L&f0A-Cheu6Lgn^rfjdIG!9+3|NoAS6? zDms*rJt7AhCMUMQVJO>OlUlJy-I%W|rE;68IA|A*%SC37cS zAvQ9DEE}11vPPJ;zbni-*(S{N9~WjB-Ey&l;YzU44rOGI$ZfDH*FrFLC?l(K)r))& z{8VhJuC5n3Wn@)Xe(K2M_|2k28QCN94C>_JAKabTm@Z{xPagikWnoikZ3R<@GO|i5 zhdN@D&v(?JjI7e)AyjESDLRyqRa!$Sm;TyVVVH93-OLBTO~XbV9t*NZI zW6+_@ZDS&Lb>w_ue09Ds4RyW%4RyXO0w+sj7hPK_ zuA83=!g7{JwFkF83&V1^{m6BLb)@2Qui`AUHLgoe$M;xd>S8G(mpNZ+wZ`Amc)Kv8 zKO)S$JTA;RjW20BTz{7KxxOqnGV{xIWXZI{2NyE!c!XJ2&S#>W^~rfZWX^9Kr|IxF zQIyVH;m6=#tLZG)bT}@c?EF#FIi%@)A-oQ0^}|Me=7(#UsKf&2(!HVglV5^f-3u*V?^d$%F)8(;By^K%4zdzjf29pzf73+uM?*Ib;7LA zM}>b4|F^8uv! zT*TXi{jhnbrt_#U=R-cD$r)x^Y)c)&%p0GxDQDSV7iQVt6=vBBksftyaHDV<_TQ}J z$mjPozE7Ct+M&sJ3Nzh3!c6yhVWxXfnCT`VzN(*L8na$hp8dj%nx9f-z&^|eNdS5Dmey9eKJ2cC3Eg{9?Gox68|G|%E+oOQK;!WFFKTwmCk;VbFSuV z8XwX4gfOogF>;;Z{O~wotPWvt?38&UPiMNSFDi1%hJn>Rm+`583H)4*XJ~P`jtF%q zBdfRzM9w+qHNv;TuhV#zW@o*~DI+U8bE(4y26w0EP)1huQ-ZM4xnFcBBP*Tx)RDpc z?V>{&*(35Y>aZYiJ4L5V*dy{bk#o-c3&NZu`jW<#h@*-TYuF>q+BBzY3>@22^)XzB4p^U7`&M{%ytcHK7#&w$gGLch8R`we;`&|2)b|@n& z`>Qma8$^dPveH>i9jWIHqC**3)&Cmm%)~#q&7!kL*dy}w2%CIRgX26}=7%z}N8}q2 zHZP}!VfCblpjMdQQ>+l)2>&LHTbT#BhTJN0%E+pI9-@wvcZ=vyMpotBrs-@G z9m>c`=a(Yi37;Fw!m<5!VfHV!(~i{JUXfEqR`s@nI?|S25*^COs@{%@oZouvr2Z`Y zgF7K|%E%s(KY_5)iIV;RWn`tpXE^5BhCf8(CmEN64RG8?9m>cak+&gi7ULhBUv%1p zJt7|?a`q*j#y)jiCW@RgvN|q%sWS)v;8;$kOBvZCa^8fsbmupLV1@|4ZbQkyX9DOdV;@Nr=z1C?l)3dPvhbTXZNR zE1kpCk#?9SI+T%BJ3K-iX=4|O4rOH3uHM#kIB%Z$p^U6_j!{S2($%6v8CkWlYLTn0lsK3UaL(jZ| zF>#L;Ib~#z$VZBtdFD3>v_tNKp32)rBBzY3@@Am_W^(Wbj&T^5GO|bH!zhA`ZU{ET z$r>k;W!%q8mgjoc90x(+qOqwlRfg4gAa|?Z17lZS{T|p1VcKRjQBHf`5@tFz!pzIH z!p!3h!jHmVFHC)R3TcS(YvEZ_(HfR&nnXIb~!OH-kFU@DJ``Y_vle*(35SusTMrz8pK(zOb85VO!Jx zkH=T^S&v_Nd}XW#Du!9e|G3vGQbKCiA;fm~G%U!rjR09$_BqH-uwh=R;xUp;MT7un>nfY2PDkgE{wwa@wCJ%=|3T z*nJ+9xHpNMb-Y%K`+zX*yU%XW=P_}|pv1mA?gXa&KWqB03ui#z9fJ~`k2IZ6g?aqH z5N4j;^9A}(g59<%ycl7Yi)k&>c)jp_@HYta_}nH;eYbrgF6+Kkm=*IBbkd&VgK=Q^_KyjI7Qn zcgz9$OgB|@$oaxE;B!tqZStGP%Qbd?15)JWB4=E8JV9)_;|Ac3*nflQkaM-XZ4fzS zWRhg9%rj1L4+3j@i7m%|X z!)WUG7KjdIWR-`rDUT0d{(OyVGhch6#w8hVpH|gLYDg}(^B$EjmyZ)EFANu#?P5`lP5jg zTx=@t4Dtd>WgI3s%!TmOSbZLOXjsm6V-5>*E}4}F$Lov91mQBUDf@nnQ#H29ykWx8 zoOyG4IUa5w&R08Lzrdd*gEYW9%vXoWQ6=C*d6Nz^V_Hz zk+(wM9n*%Kb=D|y)}=eX4f##Dudfj~>-%wGep~cM&5k>!4SmiZOTxxw#Or zH;J72xm)93Yy3xz-xB6A|A+7-@Hw$z`?>JBF|9nvX9~}S|Bf)SXdDx61t*|CN&P~w z+eZaY2j_~MZF8z{D|oRm?c5+d3;c-i0Mrk^r=?Bm|3&yd9QZ-llsr$E-xBX;s;`2{X?xX!4hZ?}YvdVaEMTn03f+XqBC4 zT-V90gF(WNfhP*He&!1Q(1Udxguj6Q9pO75zfI$f8vj~&G4k0a%x_DN3D-gXv2Y{U z!anAQHb)Duf;?N8-}lWHUIU-syHbBObgoizaD_1KG;7?V@#Dg*pHGC>Bkm|~*ye@s z*9fzo?-bquep;AupA&9{{B2FYAL@>I<9DoQ3AaGUFU+_X3I7}ZGGW@eN0{k8Df}M% zc42-q+ab)h^r~*nCF1!W$2ZZkie=$ObS8DQ7VO}S%5$4$Aa^XvH zO#_;ac36I)#UT`D{a*l)LYmg&#s4nL+%6vqgt8 zvPb0G5LPQUFy)N5@^1M57JdMI2UGeFd_V8Lmw^uDNh0S@ zrkx?obwAD%=K3B1jW5>t36w{bv0UVokyRO2YWg<`Gu;+pzTfzP#&-*|jDHq>0_WH3 z!heN-MAPBB4VIU``*}>0Gfeq$_#bIVUNf!75OaqGlhB1J`FwdO8kSnQsk78Jt8j?c{ThB zVb&GH%qQ1NsnwWa${&E=tnpshHLI8s#zsU=8QCLp_q~S1y-##_-Rpp!SH-hP|MZLQ3EWm$+>;+B!vhcVV9BYl=6K0?DAHrSmKhbnJXNvY2x1YxQkq>hr zbB1R(kyA$Yi2Mvq->31*&@*co6YXE*l#x9m&k{MybqM>+MbySKu*fMRdqjR1Ve=Yl z;MyfRl#x9mFBN$e{Bq%9+(#H@8MnZ%5w3-QtuT*!o$y-t4Z?g+;m#XDTfiTx4EM9%jZ?t2Z$xjutC zF9pnJ0>1xXez=ClAB3NQzekvTnZ3e%Zg@eMeS{;ZJ9W)@MdXx`)ivi0k@I=sgs=_% zT$taEgoL9Z?}v@~;WNkEw0|xB!3`8SWn_=Y9Zmlj_9^}IL{1r5>0c>wuI*E*@du1s zj(>19BBzY3%2KQ8uh6&?dgfxr#CVR#DI=Ajj$oU+( zNSO6-voP0dilZIL&z&NtjI8p*^M~d7E&N{#)6P@E&%tjO=2}UA6y};v{}hgaJfyLO zusYTrVLr1a2(vGGj_?ThwkA&#&VWBknCqqFXgU*x`RqGc(_w#?>C*lT;bQog3$t7d zQ-|wBT_Jom{1Rd6d`p;XOnF&{OT)*aTI7_GJtAK&az0xmQok;&-z0L%$R3g3CUU05 zaa#2*@=lRcMpo|`hfwFzu+0ZWhcdEy_s24`TzqbQM40w@%qTwt&%1vReg^&?P3KwR zeej zn;cU~5N00E6g~(3*_xbT>W_eLYw}SVpD)a{%N7V%z%LV~{Tks7@UIo-+GVxEjqsNV z-{Qfzi7?kIYZB%fW!#vbd*I(G%(a+)E6lN+-)VBLUq=1s;Xfeq+$ zM~IviTpRcDr`Mu~+M)rvOMUiui?oS&3MfffFZwPZuxk}o+K5X+-kyA$Yh`dYWY)gX? zhi!x7e<{M0pQ~{VZOZpnj>st^dqh4~Huhe)A<4WBw7CB{PRktfe&b0)ag*g`6 zqVc`LwEq)fj>|qQ%ryglEzGqC+cbV(e3$Z|FvpdDBFy{Y{|M*cUh%9j*WuhR z%(XOISXbW;*VR#xQ%3fPoO{(c#t<;a%IV0SYg}~4^wl|@3K4ZsB?eiY<9@JuH%+;E zw`*%WOk>(t@1T>(d^r!7h>dnQX91Twmyf`wQ}1vK!O2i$9%c)}3(xg}9Mx>_wm}`P zVaR4droD~A2pX-zOn;j&^Yxf8^ZP%-HvEr-S-#`KHvCkiLHn$OEa3_87m5yTP)7EM{Kq2S3;!1yXMt6pd5_2`Bdb1b4t0w05AJW+XrD5& znv45^$h+X@VpBFh6**;OWpfgB*5Mx<?3})&Str zMVkC|#qJg%zE@Yt(11MF!V6Tr!XD3Q5#VCq(2qntLD2-7yZ4wN&^r-j)b zo)u<$7>3RK4*tPS!A5<`$R3ejEb>F}FBiT7KC7Pkl-tG%i7eU#h6>U*U!k*|ke zqj4%&9T&GfBQ9lRbzJ<^X~sXe`>@eIWn_=Y*|yZY&4)yXGP0VtnMECGGw!(nJCu=C zn{m$z$e)JHJw~wrxHxQPKNrK-4J*w2Z$^dLhL@ZaX0}CgH2i#F+L$Fw+dMYr2K<8? zgN^!>kv$^kF;hAhiVkIDrNd)s-hzK{mtdnE%E%s(yT@9XL-W+3jI4BkhAHK8%PZw_ z^T~q1xoO3O*@kCI{rJgJKUriNfXl^Z_IELSzTg^9HyxYFN`RY%%|u^>t^}Kz;G$7R zmg{y6nHhnr!)D?b(XGN}qAbd({JY0a%Hrl(IF7LB)&r4Dy$+@^7d#)rsK&u?qosd1Oaak$nf{baHn7hB^DjdL|F)R@m9 z>NvX34sl2Xj{R&Ucl(VZXMan{-Fvji@7ClGX}m+@CpF%y@yi+?(f9+6Ki8P^|5P3l zHRktpO77Pz=XJ}laaizw5_o{5J)_8-)cWB(IF~4_Hai7rmX^r=5d|2aS8h@;@ zfi|mb^7}Q#Lp0`lQzg&RnBPe%`E-rvYFwuAVvSd6yk6st8gJ2fo5njeZqv9!<3k$1 ztuenDQ+e*vI1cBck|%3yYs~e|luoY3g&OmHr_!0PG3Tu*Ip?Y=UZZh~#&>J{kj6VS zeo|w;e^fU4&Qb9ZjX%(sbKaCrG_EU(6UlPz9j38g;~b6iG@hYx30bb&l^XM1o|3QD zc!S1wXxystc8#CV_-T#zYkXMaV;X;~v4Lx(%8ys$AsVM@oTc$3ji+nOcXG;RnZ}FB za{pST@p_FnYP?0`Z5r<+%e}8n;|`4vY5cavof`Aqld=%HP+vfNMkosZ%SjXCE~ z$@!g&;#nHc*SJRGMvd2K+@kT_8b74*4vnAGc(2AUYkWlG4>bN<<7nJ-RQ?k+9;UHh zW4AksxjZcD4S1c{ItgVH9oBIF^xI*QrR(Z zt}FIx%=a2fo~m({#*;LjuJK%rIS*6WS*-CYjXC#H>F|AnV!mro%y$fmcWT_Gafily zub}kb)|l@Ol$>J-(|EPU8#LxS z31z=kA6Gi_HLlUPQR6ilw`hE~#t&({Lu1a@RcYLF~^XVP8m5dtiM=e_cv@r&bb##hhxHuIsU77o5njeZqv9!<3k$1 zO_pc>PK~=XjzeCQ4#)5m+Ztz(W!xZF<3f#RX*{3Iffu+M^4Vc-By%9;|A89{T|Ba~ zyXv|e@s)?}yz4l|b2@rgou=OU)6~2FH1+;)ntE@Xre5eY^+xh}AG%*#f2XPEj%S>P zz1vRH9=}CAo&5dgH1#+i{&ehho~B+r#|-{MdAW~nu;}5@+I5lbROy`sJ#<4k{O}+3 zhKs#`rl-c-D55=Xfr$L&!Z63!lvC$NCiKX8vZLja@L2tHgwMdneYhzDTVJfHc*A-!J+vTu_>pb)4!>01*j%gvRj>i+| z5A0FKM32F9kuKxpF#vaWDZZybMrdyYHf3){ME-bh=l3JZsr*fgus1!3cazvjdn2(a zd!=GenfN~L8OjE2vM%V{F*W$A9Ct(SYIjfgpNg|EBHfqKSk^;@>H4v$bos3UZ7X{p z!``z9E2r$;8DX!aI{ZG7_Rhnm?78D}2rGL};y!G_rgF;O|3uh3277aH!qHv^Hf8Tm z5&3KLh2OVD+T;1fIC-*T(s#nPXm1QQW$#3Uy)M|}c(!sXe;-EJTMv62@1?ygY|36D zK(D{N5%@Mt852DQJDwJvu*toW}s%np=9$ zBVL2KkJpW90Ok)_cU?V+>~>upK(|LdWt$4BDsPC; z`^i`6@%s(k-Zto|wxiqoeuUmHp~vzmr_$y39eO!_3q7@ux{7!9p{JKa@zZ_iDI2;y zj=}2bK8bW0Rt~#e_jVt8ec5xzYY~HOjgIyvh0*=bIPMmMd48JwbLi!2VP$(T^b~V< z)=0FOKJ*fxhb$U-vajw|!)OCf$2J8U_p#pX2zxtdPdm?5T0h1IrfAC-@iiM5$3-_ZD={!NxKu{JE1ncprs-3kO2j( z$QgJzl$Db>p}^gPxj2@w#PV9ZR-QlE`hHhv*z-kkSQpOp$IY5mnSMt6(84R7v&vH2 zRyyy+MjMxo`|0K=Z&G~c%-DO^HGdH@ycW%fDFfMf&iC4&{@J6S^2V2Yql&#&f!7Rp zjm-Fi`%LpQ=IYvx>Y0Cy%iildG)QI7El3`3+l@yu%%F%k~Bj%|4d@IqJ@Ki^X=r+Q#sYk%Eowb_ljC zY{s-HQzqK}iu$Du4UJ2eF3!Acn%x_yU6`3YCJ-2tm5Jk?xv=W|3&vMfj2~s6KL)aJ z`-cf0`I5$}TKp`<#rUxSDLTs(JbasG@sld}fo7hF6!8{=YAlmf%0v4Z}?xdKkQT21k?9nV|g;M(V@xrIHk|#MjiTe)FCrz2OImRbbZBTKA0B$ zWNfsn zr%%_Hj-G#254@(NW21d_P3$YKjs2$IFzDm5-dP7=S|5^QV?R@8jOPjp87s6`*Yyc6J85wRz{2$eGRS3(X_@RvEzW%rR25Z{1$0yrf z_rKq78}e%0>%RP3nd-_D)`>FCKIOie2r)~ju8T>i&x~Gk?){(F96Fx2NzhyXpVx>2 zH=N+kkp#NudJiH>pBF@N44)Md_D6)zN0|BJ#^3h36k%S2I1hl~xd>YbbGXv|?XTW5v2hiCdI~?# zQ?C8M%PD6kf3PO}6EJgEO~DTWmE(7*G+q8MO~fzkR8>{wW(Bgd@$kmUEx zdcr7H#IKC?{Myc`zi_j#6xo@%upU2;Rfn3Xsw~Br0FQ%OlZj_5=TOmcjD^hoJU(iD zCR^l`kv(!V=Dj%?2aabjj~`jxztx;9wvS}#9JAe%d4J_|Ex7>xMZ$jg?C(%s2;Uaw zeHvZ#9{th6Jk!PrtNXVat9B@tJ~-JU4}|B5ocC9^9<+fnwceGRmh`u4s1K$t&kr)| z!R_DJ063O`a>~da8~@;DVxye*W7dP|!#}tZY?M<*_K2K)7n7NVE5}A1%E%s(v&`lQ z{DWJHjXIQ(JtAKt@@Dufwwa25a2v2upE9yXZ1PX+&oJiy6GaWa_Z5+tp_tK zb#;VkTIpnwt*{QC0~Jr#c&^4}8ZRbGepYF`UgM1#Z_#+0#yd4`)3`(9LmI!Wai_*z z8polmYK|n&8^yN9?mR@PLw6pcusaV?*qw(c?9M|JcE|0d&Kqe{c#X#HJVcSZ^ALsI zd5FU9JVgCL8)f)9$7=zS=^4++iHHy_VLZZ~mR{Lu>a9IZy$4TI@7dGTd;e?nSQm7> z7m}q(%JVVzgq_m+48b^TU#G`&gmL6hx%M){rriIkp4slmd9F0PUKh`wbFlF`%zZo; zM?~1GgiJ2ips*f&&ga+dab5_|U)rM`W$%&*d#kap2%B=$qnjFGkMl`*zS17=G0I-# zyQrtJPc99h-u$`k8evs0d%?L>5U0|;IU-%oC*k#m>8fiy%fsKxz+aC&27ZLFa?0K> zBJ6R#3D0xd<9$w*gX?JGuP5)V2nNK%CiaL)V_}a%xj*=IbTH83y-rZ2iK5Nai}^AVdhaeg}i3#_Bfw}daReT zu_=43bJgZ)!;2jQ5m&h$dk|=1V;Bzf8VGnhW&g>At}RjQ0&zrz0o+Ta2* From 8552799a4fcac35404cb19f04612955dccf75a1b Mon Sep 17 00:00:00 2001 From: yuanjianmin Date: Mon, 3 Apr 2023 20:03:14 +0800 Subject: [PATCH 41/57] esp-tls: Add API for mbedtls to get and set ciphersuites --- components/esp-tls/esp_tls.c | 5 +++++ components/esp-tls/esp_tls.h | 13 +++++++++++-- components/esp-tls/esp_tls_mbedtls.c | 10 ++++++++++ .../esp-tls/private_include/esp_tls_mbedtls.h | 5 +++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index da4dfe291..a5daf24f9 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -54,6 +54,7 @@ static const char *TAG = "esp-tls"; #define _esp_tls_set_global_ca_store esp_mbedtls_set_global_ca_store /*!< Callback function for setting global CA store data for TLS/SSL */ #define _esp_tls_get_global_ca_store esp_mbedtls_get_global_ca_store #define _esp_tls_free_global_ca_store esp_mbedtls_free_global_ca_store /*!< Callback function for freeing global ca store for TLS/SSL */ +#define _esp_tls_get_ciphersuites_list esp_mbedtls_get_ciphersuites_list #elif CONFIG_ESP_TLS_USING_WOLFSSL /* CONFIG_ESP_TLS_USING_MBEDTLS */ #define _esp_create_ssl_handle esp_create_wolfssl_handle #define _esp_tls_handshake esp_wolfssl_handshake @@ -437,6 +438,10 @@ mbedtls_x509_crt *esp_tls_get_global_ca_store(void) return _esp_tls_get_global_ca_store(); } +const int *esp_tls_get_ciphersuites_list(void) +{ + return _esp_tls_get_ciphersuites_list(); +} #endif /* CONFIG_ESP_TLS_USING_MBEDTLS */ #ifdef CONFIG_ESP_TLS_SERVER /** diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index a5983b2e3..a9ff17d5d 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -200,7 +200,8 @@ typedef struct esp_tls_cfg { esp_err_t (*crt_bundle_attach)(void *conf); /*!< Function pointer to esp_crt_bundle_attach. Enables the use of certification bundle for server verification, must be enabled in menuconfig */ - + const int *ciphersuites_list; /*!< Pointer to a zero-terminated array of IANA identifiers of TLS ciphersuites. + Please check the list validity by esp_tls_get_ciphersuites_list() API */ } esp_tls_cfg_t; #ifdef CONFIG_ESP_TLS_SERVER @@ -574,6 +575,15 @@ esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *esp_tl */ mbedtls_x509_crt *esp_tls_get_global_ca_store(void); +/** + * @brief Get supported TLS ciphersuites list. + * + * See https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4 for the list of ciphersuites + * + * @return Pointer to a zero-terminated array of IANA identifiers of TLS ciphersuites. + * + */ +const int *esp_tls_get_ciphersuites_list(void); #endif /* CONFIG_ESP_TLS_USING_MBEDTLS */ #ifdef CONFIG_ESP_TLS_SERVER /** @@ -602,7 +612,6 @@ int esp_tls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls */ void esp_tls_server_session_delete(esp_tls_t *tls); #endif /* ! CONFIG_ESP_TLS_SERVER */ - #ifdef __cplusplus } #endif diff --git a/components/esp-tls/esp_tls_mbedtls.c b/components/esp-tls/esp_tls_mbedtls.c index 9a7a45e69..3fb0678fc 100644 --- a/components/esp-tls/esp_tls_mbedtls.c +++ b/components/esp-tls/esp_tls_mbedtls.c @@ -473,6 +473,11 @@ esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t ESP_LOGE(TAG, "You have to provide both clientcert_buf and clientkey_buf for mutual authentication"); return ESP_ERR_INVALID_STATE; } + + if (cfg->ciphersuites_list != NULL && cfg->ciphersuites_list[0] != 0) { + ESP_LOGD(TAG, "Set the ciphersuites list"); + mbedtls_ssl_conf_ciphersuites(&tls->conf, cfg->ciphersuites_list); + } return ESP_OK; } @@ -569,3 +574,8 @@ void esp_mbedtls_free_global_ca_store(void) global_cacert = NULL; } } + +const int *esp_mbedtls_get_ciphersuites_list(void) +{ + return mbedtls_ssl_list_ciphersuites(); +} diff --git a/components/esp-tls/private_include/esp_tls_mbedtls.h b/components/esp-tls/private_include/esp_tls_mbedtls.h index 362a71fd6..4e542cbe6 100644 --- a/components/esp-tls/private_include/esp_tls_mbedtls.h +++ b/components/esp-tls/private_include/esp_tls_mbedtls.h @@ -102,3 +102,8 @@ mbedtls_x509_crt *esp_mbedtls_get_global_ca_store(void); * Callback function for freeing global ca store for TLS/SSL using mbedtls */ void esp_mbedtls_free_global_ca_store(void); + +/** + * Internal Callback for esp_tls_get_ciphersuites_list + */ +const int *esp_mbedtls_get_ciphersuites_list(void); From d93c5bb861b9ecf46efa49d9d5efd8a1ed5ac63b Mon Sep 17 00:00:00 2001 From: Chen Wu Date: Fri, 5 May 2023 17:46:05 +0800 Subject: [PATCH 42/57] feat(httpd): Allow binding to same address and port upon restarting server without delay Issue : Restarting the server without 30sec delay between httpd_stop() and httpd_start() causes EADDRINUSE error Resolution : Use setsockopt() to enable SO_REUSEADDR on listener socket Closes https://github.com/espressif/esp-idf/issues/3381 --- components/esp_http_server/src/httpd_main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/esp_http_server/src/httpd_main.c b/components/esp_http_server/src/httpd_main.c index a67513195..5724383aa 100644 --- a/components/esp_http_server/src/httpd_main.c +++ b/components/esp_http_server/src/httpd_main.c @@ -262,6 +262,16 @@ static esp_err_t httpd_server_init(struct httpd_data *hd) .sin_port = htons(hd->config.server_port) }; #endif /* CONFIG_LWIP_IPV6 */ + + /* Enable SO_REUSEADDR to allow binding to the same + * address and port when restarting the server */ + int enable = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) { + /* This will fail if CONFIG_LWIP_SO_REUSE is not enabled. But + * it does not affect the normal working of the HTTP Server */ + ESP_LOGW(TAG, LOG_FMT("error in setsockopt SO_REUSEADDR (%d)"), errno); + } + int ret = bind(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); if (ret < 0) { ESP_LOGE(TAG, LOG_FMT("error in bind (%d)"), errno); From 56fe1959af820bcd6c82d748719a132d724bf142 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Wed, 16 Aug 2023 14:33:04 +0800 Subject: [PATCH 43/57] docs(wifi): Add WPA3 support --- docs/en/api-reference/wifi/esp_wifi.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/api-reference/wifi/esp_wifi.rst b/docs/en/api-reference/wifi/esp_wifi.rst index d7c24b176..2368cbd26 100644 --- a/docs/en/api-reference/wifi/esp_wifi.rst +++ b/docs/en/api-reference/wifi/esp_wifi.rst @@ -10,7 +10,7 @@ The WiFi libraries provide support for configuring and monitoring the ESP8266 Wi - AP mode (aka Soft-AP mode or Access Point mode). Stations connect to the ESP8266. - Combined AP-STA mode (ESP8266 is concurrently an access point and a station connected to another access point). -- Various security modes for the above (WPA, WPA2, WEP, etc.) +- Various security modes for the above (WPA, WPA2, WPA3, WEP, etc.) - Scanning for access points (active & passive scanning). - Promiscuous mode monitoring of IEEE802.11 WiFi packets. From 69cf000a4aab6128fb268d99c2665700122f6c67 Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Tue, 5 Sep 2023 11:59:04 +0800 Subject: [PATCH 44/57] fix the multiple country info issue --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libnet80211.a | Bin 485304 -> 485272 bytes components/esp8266/lib/libnet80211_dbg.a | Bin 544204 -> 544172 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index e5ab12238..ae7c40ffa 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,6 +1,6 @@ gwen: core: 231e0e2 - net80211: 7b39142 + net80211: 1cfd25b pp: ec7ffb2 espnow: 231e0e2 diff --git a/components/esp8266/lib/libnet80211.a b/components/esp8266/lib/libnet80211.a index 7739a55f39cf04a0f9f6f9b8b826717595447900..f42e584a98bff70a6b9468a7b11655c52739d9b9 100644 GIT binary patch delta 3436 zcmc(hdrTBZ7{F&{??u=vi;%nW^f)nhqLKq?00WkzZK`OgAZf7zJsP8M#)PIeJ`%Dt z*w{u$z#&&?TpdnoA5LnCH|1{2&B)5gda2dkCVFQOdKS)}KxjGmx)6FAgLz0q@K}^d zSYYiC5kCIS%D8tP;U~;E5&kb8KSp?2h@nD~+=l)|+FnGShf3}06wllL z1vUvM*o4R;h>HzAZHz0rj+UgN0dY$sE?(5piMTaIgbf}!|3AbfHrHKpqP0X^%f*+m zwz#6(>5E)wbrDy4!48rd!TI8$CS-UDpgl8t_^CIoW-daAW1RV9l8kiGX>%kJgA>`!IJ1+pe?NyG{{0<7HrugH?mjy)*b(2A&)WwGzR$ef zOzL^N8zT1xL~J+fDj|}id^5i_ivP=CLa(Q-1Joe)C&W@&PPNfHP_| zLHrch4A_CoK$@BdAhO14SkC4#fSyVNeY^cFrIQ>U_kZ}-Ly~(MY%E3y{$oHt zsW}AntC|NPW~+HV#O-Pxpr7w|h$U+8ZHQ%R9)!rwfK%WBtqNc}Fvs#p)wigg?c5%g zf2HQ^p51EB?kTHz5F!s?J1T^L&^3T3IN^!4`{;x^UMwVKYpj2 zlltp*9@^i*(_K|AsrwZIkA8zk%D;_WQp6bNqQ8H!Q~GF(%cIlp8tJjdbbq=h*??zh z_3JUzb4b8j==+BpdMB(Jr?`vY4$=W|uYyZp?%ZJke?p@VJMZ%p+P3o?7=sUp`DXszB7TOB#KDbOe@nsAh0hdT8 zz?E?bmDAasG1TT2@I{*8b?AG*wb5u_46XAD=By~_!A$m5-9+8K1YAJ7y$)PQN1^sQ zd?WABUZ@q0tPB4^w)hKc4T;oTM3lz}J$X^^{)*O@l?D8UDbeK(%q{Rx+{5 z<`a0JPIEBFDo@|T8#ztMw+@gfVJCo7Ej&R)6`42{KGPzb#z>!0Q}Z_- z50WHr$iY>ta@=n2v(Vzo(MBpbQWz>zUe;^}SGzCdl&L2laTC`xH~%Uw>87MG<+Ge= lDALOfMTVdEYg(@AGI%ybLJD>Ht*?jK5bXvP2l delta 3443 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 Date: Mon, 18 Sep 2023 15:09:50 +0800 Subject: [PATCH 45/57] update the readthedocs yaml file --- .gitlab-ci.yml | 3 ++- .readthedocs.yml | 5 ++++- docs/requirements.txt | 28 ++++++++++++++-------------- docs/sphinx-known-warnings.txt | 4 ++++ 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9c007547b..ede03ce8f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -105,13 +105,14 @@ build_docs: - $BOT_LABEL_BUILD_DOCS - $BOT_LABEL_REGULAR_TEST script: + - source /opt/pyenv/activate && pyenv global 3.6.10 + - /opt/pyenv/pyenv-1.2.16/versions/3.6.10/bin/python -m pip install --user -r $CI_PROJECT_DIR/docs/requirements.txt - cd docs - cd en - make gh-linkcheck - make html - ../check_doc_warnings.sh - .build_examples_make_template: &build_examples_make_template <<: *build_template # This is a workaround for a rarely encountered issue with building examples in CI. diff --git a/.readthedocs.yml b/.readthedocs.yml index 569fae4c4..1b8b6529b 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -4,6 +4,10 @@ # Required version: 2 +build: + os: "ubuntu-16.04" + tools: + python: "3.6" # Optionally build your docs in additional formats such as PDF and ePub formats: @@ -12,6 +16,5 @@ formats: # Optionally set the version of Python and requirements required to build your docs python: - version: 2.7 install: - requirements: docs/requirements.txt \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt index f3884f2ee..a5347f528 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,17 +1,17 @@ # This is a list of python packages used to generate documentation. This file is used with pip: # pip install --user -r requirements.txt # -sphinx>=1.8.4 -breathe==4.11.1 -sphinx-rtd-theme -sphinx-notfound-page -sphinxcontrib-blockdiag>=1.5.5, <2.0.0 -sphinxcontrib-seqdiag>=0.8.5, <2.0.0 -sphinxcontrib-actdiag>=0.8.5, <2.0.0 -sphinxcontrib-nwdiag>=0.9.5, <2.0.0 -blockdiag>=1.5.4, <2.0.0 -seqdiag>=0.9.6, <2.0.0 -actdiag>=0.5.4, <2.0.0 -nwdiag>=1.0.4, <2.0.0 -recommonmark -future>=0.16.0 # for ../tools/gen_esp_err_to_name.py +setuptools<57.5.0 +sphinx==2.3.1 +breathe==4.14.1 +sphinx-rtd-theme==1.0.0 +sphinx-notfound-page==0.7.1 +sphinxcontrib-blockdiag==2.0.0 +sphinxcontrib-seqdiag==2.0.0 +sphinxcontrib-actdiag==2.0.0 +sphinxcontrib-nwdiag==2.0.0 +sphinxcontrib-wavedrom==2.0.0 +funcparserlib==0.3.6 +nwdiag==2.0.0 +recommonmark==0.7.0 +future==0.16.0 # for ../tools/gen_esp_err_to_name.py \ No newline at end of file diff --git a/docs/sphinx-known-warnings.txt b/docs/sphinx-known-warnings.txt index 69b3877a4..8334d71be 100644 --- a/docs/sphinx-known-warnings.txt +++ b/docs/sphinx-known-warnings.txt @@ -86,3 +86,7 @@ spi.inc:line: WARNING: Duplicate declaration, uint32_t spi_trans_t::cmd spi.inc:line: WARNING: Duplicate declaration, uint32_t spi_trans_t::addr spi.inc:line: WARNING: Duplicate declaration, uint32_t spi_trans_t::mosi spi.inc:line: WARNING: Duplicate declaration, uint32_t spi_trans_t::miso +spi.inc:line: WARNING: Duplicate declaration, uint32_t spi_trans_t::cmd : 5 +spi.inc:line: WARNING: Duplicate declaration, uint32_t spi_trans_t::addr : 7 +spi.inc:line: WARNING: Duplicate declaration, uint32_t spi_trans_t::mosi : 10 +spi.inc:line: WARNING: Duplicate declaration, uint32_t spi_trans_t::miso : 10 From 5b83e820d25893d479b8dceb0bd66571437fc688 Mon Sep 17 00:00:00 2001 From: Chen Wu Date: Mon, 6 Nov 2023 11:31:09 +0800 Subject: [PATCH 46/57] fix(ESPCS-924): Fixed a potential freertos crash - Reason: A task and B interrupt indirectly access the shared resource pxDelayedTaskList without proper security protection, leading to further crash. A task uses xEventGroupSetBits() to access the pxDelayedTaskList resource: xEventGroupSetBits() -> vTaskRemoveFromUnorderedEventList() -> uxListRemove() -> pxList, where pxList is the pxDelayedTaskList. At this point, another B interrupt is triggered (xEventGroupSetBits only suspends task scheduling and does not disable interrupts) and also accesses the pxDelayedTaskList resource: MacIsrSigPostDefHdl() -> __wifi_queue_send_from_isr() -> xQueueGenericSendFromISR() -> xTaskRemoveFromEventList() -> prvResetNextTaskUnblockTime() -> pxDelayedTaskList. This leads to an unsafe access to the pxDelayedTaskList resource by two entities, causing subsequent crash exceptions. - Fix: Modify the timing of the call to prvResetNextTaskUnblockTime() within xTaskRemoveFromEventList from unconditional execution to only execute when task scheduling is enabled. This way, when the B interrupt reaches xTaskRemoveFromEventList, it will not call prvResetNextTaskUnblockTime to access the pxDelayedTaskList resource (due to task scheduling being disabled). After the B interrupt execution is complete and control returns to A task, xTaskResumeAll() will be called, and then prvResetNextTaskUnblockTime() will update the pxDelayedTaskList resource again. --- components/freertos/freertos/tasks.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/components/freertos/freertos/tasks.c b/components/freertos/freertos/tasks.c index c747cd74e..61e10e501 100644 --- a/components/freertos/freertos/tasks.c +++ b/components/freertos/freertos/tasks.c @@ -3044,6 +3044,19 @@ BaseType_t xReturn; { ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) ); prvAddTaskToReadyList( pxUnblockedTCB ); + #if( configUSE_TICKLESS_IDLE != 0 ) + { + /* If a task is blocked on a kernel object then xNextTaskUnblockTime + might be set to the blocked task's time out time. If the task is + unblocked for a reason other than a timeout xNextTaskUnblockTime is + normally left unchanged, because it is automatically reset to a new + value when the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter sleep mode + at the earliest possible time - so reset xNextTaskUnblockTime here to + ensure it is updated at the earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif } else { @@ -3068,20 +3081,6 @@ BaseType_t xReturn; xReturn = pdFALSE; } - #if( configUSE_TICKLESS_IDLE != 0 ) - { - /* If a task is blocked on a kernel object then xNextTaskUnblockTime - might be set to the blocked task's time out time. If the task is - unblocked for a reason other than a timeout xNextTaskUnblockTime is - normally left unchanged, because it is automatically reset to a new - value when the tick count equals xNextTaskUnblockTime. However if - tickless idling is used it might be more important to enter sleep mode - at the earliest possible time - so reset xNextTaskUnblockTime here to - ensure it is updated at the earliest possible time. */ - prvResetNextTaskUnblockTime(); - } - #endif - return xReturn; } /*-----------------------------------------------------------*/ From 8c531f586fc681fa2701a506e5bda0b113f58bde Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 24 Nov 2023 19:48:38 +0800 Subject: [PATCH 47/57] fix(esp8266): Fix open mode RX fragment packet fail issue --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libpp.a | Bin 249530 -> 238578 bytes components/esp8266/lib/libpp_dbg.a | Bin 267294 -> 256458 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index ae7c40ffa..35e1895c0 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,7 +1,7 @@ gwen: core: 231e0e2 net80211: 1cfd25b - pp: ec7ffb2 + pp: 6f90116 espnow: 231e0e2 smartconfig: 3.0.0/af78f443 diff --git a/components/esp8266/lib/libpp.a b/components/esp8266/lib/libpp.a index 93285db028416f53da4ce9724687735c1c5ba92b..e216b4e17b065802114a5d1798454d59e6379175 100755 GIT binary patch literal 238578 zcmd?S4PaE&x$nLAOo)*T7(zr8)R|3yfFUN600BXhVSqq`h7b`wXfpXC(R`6iBv`Zv z2&mYi)ynbE3W_baVoNPr+hdPG5wXRJ*0#2#J!rWtwc1j@iWZso|6luAGb>}L>HRqO zz3;nV&HAlpJ^NXod#$zi?Cc55h;-I9T{`$;e_vNHH9x;NI5od`s^6cllFU!Pzi8TI zSKzN1Y+2SHENl1!r}yJ8x2*qL{U5GF_5SyH`|NL8|404zFSYFc{BLfw?EgaVS^BE= zU*->d-SYhZ$5+m(Uepi`MY@{nDkISb3-P%P(bBpbj96u~%ZMSZs<~Bb&Wd&!u~18U z-3?lyy1FA$cSA#cb+y&d)lt2oxv{yrt07w5(OO;C-qzT>EFoUjzgV<88|rSXZtZS~ zHdoh2qLEJ>mYj|ZIvdonkvBJKWNt zHi^dSxIvYvy)9JNR;h{~sjsh&G^>_nc@S0o<&HkIowcIA;YKweqg{<|W4pzOM%acJ z!?hR?4a==%)pcz>3zl_S#tGNlSX~$GY_Xc_lm%rRtSa82D$(2)ZRl)_)L}G4x^AFi zLtCU4BPX6fSv(@C^%T}OclD#$Ro&5zVTI<`xpqWvK!+{U(PfD!%VDH4nv@!;!|cJc zS4w?jbE8Jdp|-0_4g2cu4h-%Foq9vVN}Zu#XG3c{hO3d#+11rdrOt+B&0S~)45;e5 zTK8Oo_0Miz%m{7m%{U>W4PEHhsvdM{RnO%Z9G7=v!s&=Nk!WFd>9j8A5u7YL=dtZ? zjI>zpG-WDvbW~t+YUt{!?5VgRTE;QaQ7Of&>Y0V{UyDfHCN)8`Q+5j%GpX zS~{y6J0r`gYrAn4bYO0;>RC9axw9);dSj%yrMeum7RPwUoQ7y!Q=c>l!wt*38@d}H zMx?U6r6q*S-Pr6lNeZ{O;gsl*cxBIWM5;KXkh`4R3nF#%x;hs%FRN(piiR5+%j#R0 z+JP7f*WQYGhV@hegwg_6VP0Xrvzi*1={!tpi9{Bn|I+~nL|UqPcovf8U=XQR??Swa zjcQ?Pt*>ruL8G`WU&jpkJ&hW0=HXmJ+o_p{6MkbqF-)OcE#j#d&)pq~wSdE$XDrRM zHndi&=_@BrY717ESy&_&G}l_>d0ndd#6?`5E7ZB6Qm|^2*11YtK+wabbsRuS zB*S4rMfge;m!_@i;W%vXjw<1TMd2$;mthppUTOXH-Ca>8<4kBZYN4irwn&SbL~z2m zr>B&tvLV{JvK&jKYq6?FHGAJI7j-AfCFPLagD!|jWdo5U#YqcL3Ea^VSqZ%^6{pea zuBP@Crx|tqO~O#`#`@sSPt~1j32R!(-VdrNxYM1GnNZ!rw!^|`b=F;}=Cg{Xl?%Ao z=y;V|IUSX{>S!4IqPPe{U=eCbTR^pS>#VD6z%pxeQ)gYNyYecfs?Itqit=3E&`@7l zwMcP$Te!JPmO&9L!V0%Yt*=yWZ)04wIbyPWAOZQRRYxr>V7*>Qk`b-0<+eu_B7GQV zV8cpZbdRWS=%IFdTgyr=I7+?$*`U9ESrNv*@q!DS&q}NT4b2cUENBx*QyFtRk?ArK3cRVS{)b7;-akVs#&eN6f@BRu1-xWI6O(B6T>~ zk>?!lx|AtbRNC2UMhp5;DbPA|+B@qSaN15;U|qgo-n`D`^SZ8RbB~tubWZbfH|{ob zRcEBFi?fBUG4d?M4v6!X7KN}%*T-X6(b`*@>sGn~w(RE`R?cq2wBt%-mG3K@*Vfh0 zX=q**p1rtw-sM%ZD`zjNs-C@g_T|!390twU*51_6uQjzV#xBcEoYlFq16xbZ&wT_k zR9qQqQ@JEm>P9Nn79*r6 z44dh;=Eg?m#<)HiyW5)UB3O>OPgM!bN;KWQsggGIV3yJb;!9X^v3Rjj-O|vOSOSwP z^=XY{8#r9oES^uYmHu>S2ZJ9qVGt#wX&r>Qs1{Yr&Ch(#NG-M3oet~#$Xg< zGaecm*J$Ymb>~X!D)azOzAG9V7d4>S)deyN z&E3F1+}&Gh$-p!f?QCz!Yroikx;t_O`T0|dig-t^7@u@CgTFAle2#6~xH0EC+q%w5 z#4M{~DCAztDpJWgR>1PRidG6jkCpcW%R1*;%lhUwEh|0UvR+tjSyx_ZS%Yz}?{~$J zPqeHv&$O)Nqai=rvOdhTtlPh8S^IFGZ!L`0j<>AR^DOH-!!7I9VV2cR=meo1NvbLXNS>H$6B$Oqzz1r`8zr@L?++LlZA1(b&?5a%9oJOnQaLnhKmNIQ! za7Rk8Dzo61F{jGogj1dHIOmZ;({?yjBc^5hGK1S~C!80of_!MfD>3KmsZP~-K4;oK zCp=|Z*a?paKICz}aYnFeuv2wG!H;6T;H^K3IpIs4@CAVvV$+UJs}DZx_00`d4Rz{A ztf|WD3||*`E_U~Um{Wg2;Mv$c_2)VDS%ABrhh%i17m^I$%E;5P?axAxc~5vw;OW>s z;l{h4iTUb$S9XSPsSGc!4Bz-r{m6Uj{cEZ&t*x3^TQ%LO8W#*-?o>?)hTEJf$Egag zsS4fw-Prc;!=Q8bT~Y?R;;#a&OP-L?|uw0 z|DO8XyB|eMTpkR6&8eykhQIDqEe?jiF~57pTg%8J;Z;MsdPg%G<)>$8{tS?@;Ew+3sB-0l@2(yiy^+mN+*E>~h!SHXLs?K2e z_fFM~!SJ8&sh{Cg-4qOeSXqCmQ*}!)d@42FN-y*c@`dupetD+Hm+2qlcfw1Z@G2)< zf6dV@#BsSe~JcC?eA6behLc5QA&~Y60 z5f96>L?ssUTK!w^K8YQ2hD{t7@(l7l^yE5wG_vh|vTA50@?4kZdoOqP+(LWw>}x86 z+pQ&J{bDVQJ3?<|~D zG;Pwd`pJ`nMRf%e{Ka`idHI%)Eey|DVM(;1tt(PJkN20ZTr|77G_>f7@++%mSC`Mj zDq32;XlDN4($Kt_1-#P_x5^FFTtVcVL6_zRp9(2X$#D~TtPN)PI5PJj%;N_fk0%!( zq^R1EBdVOX!#rt+VFo-^v*77yN4x(~ecGUXhNIwVACs1H{nMM(Eqc9uYgc52}1`sj~zW&G52Oh}T+Yf0Bhf>-r_Ld$D$K}a~SYEv_g3Eptt zcw4(duQkF*<C!Dv>>ce!_E8)Ccj11?Ek11E^wFVifJU%rkenwKo5>yiJcS!~gEv_Q(w*U7G7oa2BToxO?HrJi{IqrrHa_ zoI#EW^9+1Pm@WIEFwe-Lut7Vc!NY{HMX=5h_JjSxIp8tE#o!6Tx!?lfY;ckA4Dd|h zeDEyc67UM)F!(0n8t`i2GVtxf<=}gSE5QFITm{}C%zk=In0<9bxCP8H!8+E1|0vu6 zepfgO{y?}1{CD9V@I~l!9{Vo{zlb>bUW9iG>)BEF5zpi-AbMDw6f$> zo-53}IEE-cAE943h>$ZY}IRqJz{YUcT?+bY-KVuQm5SCC~)E+w;b=<>Q&wnihh z2&0{D*rchY8JEwImSA3yl_#9n_nXWlvHnUkNi26Bla1&vIg_;eeA}59#f=^-k5`>m z9=@Bf@;Vz@B1)=?6^|tsEIA=wwB&?%;gS>L#Y;};TfokC7A~*7yAyXcZ*ad+Vo8-m zE+$dzy7t!A2HZx<>rq?3JoVM0TbZ6HTR>`t2(D5)+`bvWC)YZ3XMA-oN;*b{rZs+m zdY2AR50|C`%2%CR(AB5)>B_fufc75z3_Z35-6Qa1nR4X1n<=i-dXFN?Q{l7po`6nr zJL}ytE$VjOEnGq&TrP}rJ-YzRb%c7H&z^%f?cIxcG7B>8w7vg;fLtO8hp?^U97ub# zqwO6AoA!2|#@;XFm=c6^#|(R1tF*ljz^1*YVQ&l%5U0z>dCM#xE13@&%a{XxxYmly;E}xTRZ>wRC?XB&Vh&>cb zx!tf=BFsR`uY{gCUXDXgRZMhszRScO+k%dITtl@(vO25-Ak(r+a$ulXD~S%HYs8*T zx(0gMHf6L&cQb%xC}9LH4GVr5Lbe}w*i2)8d@0G^9Y|=>Mv$)YjwE{(utz=G8x61R zQD3(a(0U(h+#v|LN9UCa^*A0d+~VgN(AtN}FC&Pf9Xjsy*|gd{g+g!9i4bb+Xyu){ zg!}A!b_MyxO8v9%*&XF1f$(@v^GYd||Lf$(|seXUMSyu~^(t0PGQ?hu0u;xC|~V;sPJX3O9PMp>8I=2Uv`q$ zM?7Nr-(ryuVoT20n7ZYhiY2{eBYfvvRqW~9W^E4lP8{12?nOLk`_7mioWdw=YIM;_McSjEhBf{Ww%ECOa3K=!Pa^HoU!#2{A0VOS6+F!KZ@_X<@B8H&+i$V zU#z^pyURb*KeiyhzO`#G4s8AO(X%S9^y9%Wf8`v1dz;_?Pab^*zQy#@1dsivk2dpe zZ2V{Q#uo|A?f&*gm4BiN)BR(E^?76SgY{$UPE+Ujk^B-iQT%`A$i77%z>yVv?#+*_ zs($WGx(l@)Tg>tn*3Zu=ow#^n*M!rQy7Wd|CoF65f67wALhDsDaq($Q;Comocjx+} z?F`+F+Wh$X){m#Q{Ct4z(<7v#)sLI69j7UkO2t!au!)BQV71;=?CRt);$XS z2Y5ja*R#hBm#lX)e@ARlny;+5>HlB)%-q}i;v2tw<&S&M{Od>G@gIrWFK|X__58*Y zxIZ>+*a1&Y=C$4lcHlltxueEq&KOratvNDnq5U6JTfRBw8(DV7l7%JZy*=kNMdr@1 zeQ8_ll4n3$;5JO~Ct&jUlwK#|nL3kcTLQgndpD2m zEpd8%SsMzK$iBT`vqQ;*(h--Y6|9W;&e`cL8@_ECUe8C&cZz5hDAAQ~%~*ZY(g zljZJbdV7ZZ&i&qHw(raXfsec$t9oA?zPB~Dc}4FQU-9V8U+H~wn|=RG&zswd{M5j}-P|?maNVcm7qywr@!9v%QB7_P$tpd+LM{R~LMezB2IA;Cc4uU;2X) z+g{5GzvFSXzdv!3Z}=}TH+#1XD_tC0xH$Gep}mT!H+z;0E3JwJs$w&Twhpm-D04sE z<8pn&Ur@){rDd^&Wjt=V9A}r#i3R5JIG^3Bj#Hmo3fve`g zHWgF`Qc9=90@GqgF7?|Hb*%bykG$A7{BP>WK4aDyH`aRA%%S#T z%1S537EX*6+gR%tF}`Hjf+2P#X@Tco9N&n!FqB&A#1@W;j43e4WpxDAxmFEGjxVA5Ik zc*a$p<49(n$4)K$<0;nD&lKi)A;HLVG~;HT=TabfzIrNf*v&JG($Zg@TKFqB&tdLi zrN21!j(6cNPO~ArCv*#0U z=@X|GKB3BvJb&+6oVd)FxnhbcOKjopQ>EWRVLyJiH&=~;-%_V3GI6mlbJ=9-Y#BB^ z_VK%iN=q{)*d-zV{IQ!OrM}@;1u<@{>tjoX9a`W&UbxzRg~z?*`Hk0pnN)hysf9P4 z`owc+rXPmwA1hh+sfFFF$q>~vFSt3O5}Qvg7&`MTdmjb%bNnpW1W}W>;LcM^yfZz4 zJ5JfpP@MMH18=+xx;U8674 zDaSUj&(;|G)SzcWFtk=IA|CRr3wkzA-IL<;21DyYp4)<++o$dsgenI^x9N=4ak$L5 z4Ju5}N_(;p-`<`wR4nNDQi9GX-`VM7T2q40ee7>on?HMP$v8i(_};w?MOO~rI`{gm zVh_R`&vXaZ22S0%l94AR%i~E&8L4%7ElF1l&+A(A+LrRuIke501uq8N{qo*F#xNwE zmh+u$9;bY5;14mUB@p;MJ{@Pf$5}eZ-N8ELJ?<8^;7AM|iFLp}#vxts+gRYYsG9wI z6+0XY9F8&ZcZ>#p6$@@lwck+udd#=T{!gO&*|+f*C)VrL7B0nOvDkmc&az@F5n=lr zk9{dd?9XNH-Th`Hxkg6pmV{vMV|E`%W?8Y ze`(X>#ZI|{Z?%Kl&hx+bWnaq7vz)yd_8(cYmpq3(c&ww~H!)wP{og4`os6?AxZo_G zcT$@DCM9>_>daX>B**veQlILo(x1jkV#7)b{fJHTxT2S1ed7la&oI(oWc>JhJme$T zJC=9*t@e*;efhpvtEYV3Oy8uTD{bE(cX=;(CYG~{hP|tz(<+NSICh$+ICIr&gv`?K z$BLbew}O53$aR|I^G@3|_56%rnmrm14fum)cCL55Wm)CkX(6l?-(^0Y!0=}SnXd+h zy&1?j@z>0~6?!m3PdhcfjIsHJD>AK({DS3wv&-Cj=oHLHc+7udhvnTcER^+9a z^K(1ssoC^iskr`Slz;CFu{U!^HQqAl)t1q7erz4e!v);6UjJ2VH+4HN zee9q5<;80Y8Yg-7=U5-kJY(w*$DKcW|6Z%H)ss5Mg01xrS>qOX=KRpw&-+u2ZRZA_ zh}l12ySkr~hS=X{EY)K*UNFf19@*zvzni+A{TErQUiF7F8ncEv<2)nQU|3$zSn1jS z->?a`AEWBqp`h)zheBtn*Z>{6oFuriG{fM%bnfg`Beweua->idq z>v6-V@jBnDEu-uQDV*~a#4k_T&wEIXZKDEr#q0+tcRz7G`mf4L<@!6VahH1b-(k)9 z80S~xrJgw{(9a6o8nf?K`sx#AQ`cDI@;vKTvygW&WpU?)z&n+h;Qp1!$N9-8Pdc9c z6R5IYsXY6EROGv!)YoEC7w{`!RUPn8Vv%LBg-x*n?2!CcS?ZEOPVPCy-fP0nt2a*% zk1z79ud`G_q$XAp>a7U(=7)RdKIz$itrb}kTfWpiDv>hPGv_Mz0PIIAoZkFkZ(spu zs9F}u{q)tYUw{HP<`to+*Qui3lNm4SoVixKsB^+#De9b3YyGpFg~qjc=3HvMGA;Jk z>9NvcHDM3wISa*ZO1Y^J#lF69e4%ImWR{|M$gRN`iqKKmTT|FO^(jwkzAMgmdOMun zg4|e*(+ll66RkjY%vL)o7*a>V60{cjW5s7-N(BbTTCB}^F}sjuezRrNdY+?iwv2AP z+_QcpI^bj9aNimJuC*Qh=)unPTRO(9z1g!hGcY7(=cwAN{ZlG#T01{E1+__M9Ny6R zlfOf4QzkB=4!7luYs?z8b&VR4!_hWs%fwN9>0oDDiqkUM*Xgv3N?U#)^7_JKr6+K^ zi0jt?T*2RXzv-95UL7;am+H%UF;Mx^M=zxw+PAi%e(jkBH3xD199^87+BoUV$}#6J zo;+wht_L>-G1Jak+j#y6cdfyw{e!B7`dpu8jhl4gxNAq-M=A6sn_l=9uC3tI|}j zsCINe50PhjDs#^d?4|ja7+?R>(=NBFzN)UcDX2D6dp|%OM~&;u+x57+sql5$>NcEv z56=CBhA+!`_9LIyk23kA`)$j9M-?a2*b3-9jmqRSAIO{c5C6u41MkP&8=Zl7V{YDV z&KSGu{-1olOWo7m^$VQj*u>`S%z|-Uo?z{0w^q(J%gw|6?Eh#fi@Jx3@%b_HaX

Wg4Kju2#YWxq8*n5%fVN~-@&d^dSCQ!{FwF}I*4{fS9dGPG+h0e zEYgA{*L2f!S)|1C4vN=xoprK&yh(dIx_Y$pRIq7Q9X@?6Y_Miur<`JVeeexzc7x^W zuEdyYDl&V8)bt5Xn*EJhHo>{c{!pEs;N%ycs;j|Gs&T{YBc&(bsrn&d_>B#Fzfm`I zOILgoTUF(*snIUs$H4F-vHglvyNOQgZZ%BeF4lFjpenRDJG;lC-hbLxw`Rk&Tl!&Y zi-U}xlhtHmRn?%zx97$88M@`Vi4$V%{c7<*T z(1iP*q3qrN%)F2^wUv`qS(iPlEljr3r1`Pzs&yqpj*PS7SF|s(tD|%$e+5Wxt>{Pj>Qfn!HZ$9d%){Q=A^k zs;PTtVw)plEKK*`ySk30J)3{08U#r!^dxO?DPoHST8 zCr(9PZ4jrDFz3&x*m6RY==Ki{?8oh19z7F$sy&rpy~R zclPXYQ|_EFamJMB*=5e*Myh6&)1;BXu3zoUjZq6u1SkE6i7qfx6sNrS2Y1aDW7nO# zQQZBKyN%pori-K|(^!hju7P!%+I}*4BKpnjnAvvL-pdgL4Xk~>@P4)J5vNE!Hz#Ji zn!3@+{0}p0M4K&)Sr@S1P@%aot(&~*6Zmb#iSkrcxzTBaE9th4PV20G7XMKY#Kw<3 zlC1&OatUYY@b&8VFvHS;v74M;n8v98CMRMKQEzN=iXt~zyU>(O%X>qzb+dI=!aNws zQ0BjT7>}zs!XqvIXN6(huMob~8dfhn##$g@+~*KK&e|m5_BuSlIxOKrh9mfZ;H(fF zQk-l}u^OQ7Fax&$)2zaJ;oI~qrB~wb(5o3-3D2}15qno}mY#SNw-dd}L9%t1^)dUV zICZho$&SpmnnQpZ>|n`QmX80fVHgkS2rsa1s~28mJtX0D9e=mA9pQ3d4qHvOmgtW@ z5Y&!&zfCc541X-?^#O|Dsh?kl(54->Wa}O)1CJq|V}e|SdCs-QmTcXt$6cB6BM{HR zPSWxBS&Mw>*CR}QUe1%P`}KS@xxiT{Feb}grN>LP0P&VKSgl8RQm~^AKWOpAIR)HS zeaOl*ZZ0e!=Z&O2hsY#b>#ge$W`P-(Y*pw{MGUvn;YY01VvqAa0t033mIS&)D?hRIyW%)15>b!c;E zg(RFV39b#68nVj?t8ULZ@fjO*jP3_v#>25sgf^(L&pAaMAJvR5zx{}dSw3%e7^bk% zjXY77 zs6&o8Bz%O1jQA3MJ~n$Jc5ts_BTtSvBzys|XLDL?$Ps%s#fHs!u^~t7*>tAOCQHrQ z;WX8s$RW&iH<)KT_$7?5RGW7=X%SW)t`wX7xQ5o%VoHuUBz#}tSHmx-JsSt^2I0#E zhlKBouw8*2+;FiWN9@h2q&n|(+TnPO-Rb0HRMFDC+i}=jP;jV9ZQP0HW@)8sKrYd zc@cnP+t_O~)H|4dxEnS2jrs{GI{wCu(M`fG3CDvTPIu2M;*ju+L+XBeoE$ZBmlGf4 zk4CpXeC*ID(t=j5tJexGU5<^!DV&&;&l?`r?Jp;T@SBkLvb1pMC% zW)sv2u0faTf{h8tuM*5YqCYtS&jN6rPuj3xBe4;WgFjku5b=D$Lw*JPXwy`6h@B>z#Lh7M>ijcivs%orFS6kckK{ zgVqR>Cr9jMkV~7Fu!CzOHspvy!j}lo2mE}**_E`$zf*-LM;s!L{PiF}ucWt#Q2}^j zucXBYdl#@@hz&Vn?=;mHr_CVY^oJOz06Ajs%E9*@tQdcBY`_-r0-GdaD|~ih@AC4r z@Z^ZS%S$P3Hev^NP;AH%dj(>g{UZ17Lq)jt6&!N;i2gJ>oQZMUZk%OTy8x6$o-Pwx zNO*?5GliWnoJB^?+ZqjZzaSq(kbNX1JY&7I>|fz*wm)1pwlH>+;kOsu4?Z8cJ-&y* z_c3^8V!w%%sc$k!jdHg+$ z`;W%DR)RC(bEC~w@O5Q?y8`P%$GH6u!7CZ}0uJYD%IYsz!5=7?2`3BgY~%l0g5l{$ z0H&q=Lg8t@O7J-N4+)0H#{&$zLIMg^Ndyz{0!p3O2USmzDi2rn1*Tp3ZEwo@lpEN zytMBKPcFiMmvK6c5ESDh}@dnfeN?54vrm{I0#?&O<*4S8-<7G-fzTartq|xD;S=&OfYry z{ZDk*t-QPA^?z zVmLRu0o|WQ8JJzhyRWb{DMXIg6Phjj!|)dgUITxrfpwRX0<9FD+)ADpo)86?0s9ua z8Sx(Yzcw)Yl2;)1N7|4h_H=k7C(l;YXEN}6z`B15)?JVVLjHOzA`_52iOmz@ajXBU z1OyygAk5pvP3xWA$Hnd8 zh4Wq9Nic1@2)-VE55e%P-hyc}STHUt5%(qrAzov2Nr6j%xiN!b@Z+#~XDo%ulOy)d zSY1#lT!=P2rQmp+i5Z_LxG8*X-_aQ zA;Go876ztmbHOa1UbE8cP&pF8nh~4F$-AAikAw@bgVPxwb8#{}^5lp^!ZX%O%eXK* z2b@kD4Qp?R@@(;1&|F$&tt3L}D~F1183 z+CJqPCBh3AyI3DrV73CCeM(gy!f#M9rA)Y!j?p`>PA$k^?eaSRDi`ac2%a2qNO*lx zfk%6~UGF^rIG%IVVO@zs!gpk&c|Q}Gh(_dy>-|iWf@0P8!%j*h714BFId%DY0>L%J z76xXy=xknO;j~Rx7js{azsBItxL7wI&m}nGknn(c^)v296L&6wFfcD`bogo4v)V}; zxYiBo{CQ%Fvp;tMs~ax6f@!Q%})!@vs-yu!fiG*&~8Iz8-GYVA?{ly0r6 z>1C=5B(qifH=X`vJoDfV#Ud-gM-6=1z-JA7USqWj5`5U9D@Q-E1@phe9_DCA4^KAm zYy&Sg@B;>Z*uYf=<^V)bGjhNPyk=m&C-jWY82D=gUoO&!yHcMVGgD9Fo)22_;~}@82FfhIc(0eKWE@%4vq67_`h|# zjjH~wv%qevx*l_Sw8?jibf^(x1Rpi{DHoJ>@^aMg()$8=GQQx0{Wj8hPBtqTQhLcWCf_LgPM!r4N5m0ui z`icf+s_7|sJykz?z0@z@m6f~2tfe_`p>UTB9EY2d$A=A^N!&+mdDQMuQ9LtW?dcTA zkLJGPBn1OM1S`h&ZyQK-)Y!t+Tjr+UaUD{KZ3S%=Xif6?+TX;At zdS90l*w(0`=XGuEy{gR_C$HTO@Vugxvti*5-QeC_jsy3_#yDQtK2h^w-u?rh`Dw$v zpJAR5Qm>zJ+O~_s4a<~2Z`cno?E9$Hk5QVQKJ(y>?h^(}bG>0cLrtOiG@p6CVLs3> zU#9lM9HTBiW-3lmWR__lQgIX&$6xw_3OIMupejG4^TTH z->#3({27>gO*z3ZpRazT`D~y0F__~~Nw?%A!~97#=rbp;`PSH=P2scKJ&hY`5lJ&9qK`t zx0&iQA8nY=^vu=X&ao-#{O2h0na;6E8S@OIS)LL6!>aHL6ybnRa}CTFBKkPCyA1R1 z)DoDt|Jr9BMBns|#azQYqp>>v1rK%O`VEo~d#?fK8}>g}EzhAe{e0%-hWP@+e2JO~ z^D@pCWu7!64D&^X`7YSuQOd%Tk9Pc$t_4RKm2rTXsW2M~UT3)*wv0pXwtnYRs71ty ziU}{IlyT&lsZa%lD!Gg-F%-V@Db%1aZFCvhNiriA?(%SYk)$n z&;&82!el6TwYbMn=;c#L$Fo|VR_N|ico+($NXc$+uc2_ePoW$Nv$Vn#pTbEfREolV zhQgyhg*{Lx(F%IJ8!XGQ(ape>X$E|j;eKphI~?{Yd<})4>0@!gSBCeY;2n!qhQc|Y z0-x8u(q;J6r?7A|Uh2!yTx}>MG^u|q(s4s9(+Y8jF^@&nSj!rZl&r;rhC&yg0*B3K zXoX^*0$+>fio!#N!f2lYKQEY|6>jk<L((E=7!aEVe?y>(!4L3SE5)i=mLH%h1uMa25*bNXc4kG8Crz6gVRRYw>SI_yGd= z(*lnh0+0FxUSlP65!U;PFk-@$N<3jGyyjD=g+enbw0zm8@Gum-4z)$y(=)cY6OW5r z0*%%4J!6v!55U5!=95Mq=_&P_x`mglECn%UQ=c>xo-!2r`V=_XV-H==UOt7dp|B1q z+0@$%g(W_P=}<`13JZM-3nyNw=d*^wvp$7oP|z(^w$-OlX(((r6h81NR6-$Mm*KQe zp#}Qi{%P}prKz zI1Po2imd(NQlCJ0(v^nXX9(Qu6R3qiV_k%$K7|q}c+IfiP`DF77sJO+w}H<3w5J>O<6CPs9;#wBNv+?+#ZYjs3-O3Cn|O^;xDT-r*PU(IASQg z0J}JZ8(^c0K*8q7>n3lAwimNZCDb};sbBaKEJuQ3CP@8@B;d`2jxl;@cj_g?;7)$o z9Y%~^V=^@n@BZw|JpS2*m>=}IgEJc<$~+F|Q3I}9#*4#!dJ?F_c z_353R>e^B7w_Ip5CLe?>nl;Qw{n=4`v6Jr^-x9Ev4N9%ne7D@kD;7Y8eXjNBERQZeM^ ze_s)ITlwx_YQs;^>e<+uRlM>_x@!5nofBR0S}?m|pi4(t{I8q4W^RK{C3=P2lm?wT zc2?iK9XuY59uLk;uy;kuSXsa_XJ6)nPi=DgkG5lSBKyqn>Q{wzr0Y50o8jLk$2aR+Z z+fS%5BOQE(0Xjt={>qU~lKqO>N%mc^`eat;$(~j}l0AKyEghxVL8I!iYeqSx(!07X z*0+wXuBz^-?wtP0yY+~-IwhDF@D~*3dcF9AvmU)(e_oH=o(4amrJ|?}iqiAgzwd`0 zSCoJ0ga1S1+zE>EpZG^kDa!vJzjeN%1bO&9|LzP$`QQ906!8D(ga4BO^}Y$pzvDIS zxN^?7T&8Hh=aU)~?Ys|K1OFQLs#Y|szhr=-{a^gT)rz(l1za5D0sh{E|L5M;cD{0f z_l;3(K_32_enq}w```R?2Naw1K@XwUBZ&kO9OqisFE^pH^^hyg) zsBck=(BT2MgoZ@53>97C4uzw-GEPjr-tH0Ai?x>G?myW(ZQ0%Ngc|Ca^mb@KN*5#k zPcOS-LbjB6@$-B3{-Hp{<+wzCNCT)u=Yo~3?vFtnTTW)UoX^SnN zM}^ca2Qu>1&?{*z#r3))T9kdSwhS%Tp9rP*C=I>eGcNRc&!o_EJ)EJHJu*TwdL)GY z(la6SGvrN(ySis`C>rv)9edc=hu?inAt6yal%JJzFhs3*8iu<=XJn2_2sDRfVd zn9zovE!uUDtelL+5)b~K0e@s^B`#WTOR^W{1-xS0m9EV2&=HPXRF6M5H|M&^J$e>Q zzP3Qj{??6_PV zD^5_%6~$8^R*U;74v5bvP7D8a5V2wbMZVZaF-G{NLd+Mlr#iZ-eMN<)#fyzo9kJ>L zv2Cg&!*Ntql(Nu*;qebm1NnexJq={OrYLry+MruT+9N7R7upqNllW}6mZ}~Xo5(E3 zf^vbVXzNI5>n}XlYRy{i9h;VD?^RHkAIcq*sU8j=%64>f{K{7_%VUt6oQ#PDIL%~7$EB1)W~$QH$yLo5^bQ@kQRqc|-5 zWe|3;fFe`uqZlH5!yz_^*~2Z3F&q`VR%{!N>OAUHlrctQl!Nq&*5x371lgChMq`j( zEhNS4f?5dHC@d?b6m}pE%PAne-6RUM<5h)1fF{Q8C7qB+9&6zT+N*=SRB3a<5kC zXc46-cZ%UQEmfTHY9;@&7{aLf44<~=w^bh!zAsbDw~IaBsBxm*am_0_+R%69iTC2f zSBe!jHCMFrIa-Draei-_WRo4M77R!#<$5Y$XB|}xp7j(+=_0~ZkTdoT0vf3z=*Q>d-f9d z%(mYgdZk1cF?Lk@ms9o$;<85_4dJSr>|b7Kwr1sCd#qY1?%!+AaBR&`l#ND1*6+0! zs#8UackH~tu6)OSUAyl7zy)n)De?F>wIqA59)aADe@up29gZHQ{lyimuWns?q$2lN z|Lqlly;^2WpaOTMF9a%l{*_HyMc)1j|H+E(B^Bufnk%!TH}jNU;nTA(4s5$weYUAq zQA&J1&&h!S&6#g2_j%{_&|QjNk>)K*Sd!oj*mRc~@TGaZ33^3m&vtKWY+(Coy+ZfI zjni^RhBo}A+!yQ|*m*WLEwp^U?y|ckrt7}+a-Xkcdre^HnH-n;5cBXXbXF?mzRpY9 zl&XsE)2Ec!2ahhbDFL4^WlljrD|Ok*cg5Vzj27KpeX>w>#or{1~U@(EBdFZ#}+7QSze=-S7hjWYdtnkNAKs0 zVD03L+{1_G7A(~YI(9XRjIz;YAG63M{`Qf&s0HUr>|Cqi^krPDmF6gk-P{43+nOaj zi#3Z=VhWbF!Rf`hof2>!aRocpDT;E$m3;Vceu+59Ik98$J2$^@$Z(EL$QAGSQcX%Dz%w zis22}Z_IcsTF(w-baJ7xy4G^}#ByIoVjDGxTnZ+-8@g5NabvGrs@2`1HGE$^ar{`E zSI;DU&wLuR(I6TF2B(y0&fZ%3!WK*7oHMnmDj47IQd1Vy*C*(E&!&9meK&Njx+OJ> zi}c#A{ZMZ2yNl{`PnGz*`pz@CdM!F-V5CPM8J!+%qg7R)0ev5=(n_ys(mO?a<_2nN z61R^IxKzEB)0>(*aAJa96YI^3ZRl?Fmd_ed8lFg(dfmisdbV%i5v{5WXVg11x;EQT z`MXp}+`OM=o_igQuMbqK*!R6GMZBjluS;rHeo4^h(|z7?(fwTNUM4E{rRf!3y=IoT zbL^D;T4^4-ly^^DUA}fKklEdJLW?>rgkUaV&qIinSs@BuSn5Gg|$h}#h7uWk&a4&M`B zm!zSH^R|>HL?amze><$!rIg0uV$)+3*O6GyBy_^V-Ms25mN+rag%M=m!bZJK^w8+? zH4g=9?E3aJbvYx?YKhzJ<=fLxiNZihTy%~@739ZhzFQhm!mOZQ_b5LXSL&)a)1Rg4 z@zGbd&hmM*tl_afuX+!4muxOsv!-8kPAl~;2Ah?kirlFEe}WmYlJqRB`=^SN zl(L8e+4i$3N4@>ecaHL!#bxLm!F+H3MJRt!?y0~P9`uw*2Z1T{5q(57dYvb}EHyOh zWIZBN=8VRWS=^+%TDm4`br%7k4_u@_ms{@ByX1IBgkEv5uXoVu3Yuik=)sxsqQs_p(}J;jf7KY6XC2ATRYy?=`ZxiFc_$O17w$;@Wef&&3=8SsmFYE= z9|Sr~*{jtZQnIxV0*=J9J)O^}>4(OS)jSCq9sG4qsm7(Il~ySq1l)Q}O~zwd>3Fs7 z3GlVVR|DYU)|`{osuiloUgAq=%q;O{*wf=2`}b~4ymd;s4}-Zk*6&sGS(wrXF?MHn zOfT2!ma3kZLosJ#oLv=M-%)D&o*AiH={=%kl9uVqT8InP%M`fs7y7zvnB)7$*`<2d z#Ay!0qEFmC3Bz3%HI6z|DEEDNc8=b2`3C{ys25D!Q4{d_#zmFvXc?$cYhBbSMGuP7 zqtvc?m&GN%jLNjywYuiq-;_9WOdwkIoGjR^)s0sZUsFnAR9w~rS82|x)x^g~mA6u} zwb7fks?n;i{%oce*l!EiPE3h+1ovD~SFS3F4lSVny#Uw#o!0-ub)-AWpAtad-BFX( z+B2zNtGj*bL8|1a>c^Bzwij)&|R6Q{QMkc7uRa76$W$cavw>`9!xUer$3x(9YM zs?>L`xjU-palF=M={sZ9?Tj5Yr}WDkwbEp@_};TxhbPIol7{<5_hLLnSqiKus;C z(^U+W;yE!UvYL$`9w(t6Qa$k~RY}W!t#YE(N6%hHvgV-2=FO=*vNBd(My+qY%ZX7R zBJy8*c4#yL4=~_K2&}6|U?~HGa(v^?dh@-#asr;k>3J>vSBZq{wCteIn1PK-2dOt| zX<*9UxV{+Be0oKuXX*YO`akvfx;K;*8>$zm$lU)%%9odGRkezz)yayqlNG5aD>_#d zD-)w-5B;m6M=RL}2F3+4@>?ecV#5tbd!p1A!;Er^Q?)Ep{^OYUnch!d}0 zr@7TM@%D9Ew}JZEf;g>el~TG|QMyiSX#em{hiM0Fc!_(9u;gyow^ms#5t-w zqcl;0^FGD z@B91=t^ob-F$E9YjLx1LsML3AYI|{Ps-_3i0$2zAgM)c%md;y0_m+uT)hNXizo!*W zaE$69?R)b~X36M@_Uw}%Y)-`0P+}~)`o*AAI2d1gnXwS_B!JKiBFY>z`lCpZUOc$7 zdgct2M{RHQWp}NrpMvyB9`!W2(%!u6GH{BAM#07@Q8P{J)Y@B^ABb0Ta}V$&bXE4P z6!p`zr0CC?0!ue`>(9igXdDFaEHYa8(^zwaFiyZfASY@%2?--fk z=2B7j5MrdmX#3_;J!fbyP2Z8G&m5}mGIVenFbFT13k~&+h^j8`oUWzhWvMSSjA3rn zkq=6zHkH>jm18mbLlduqrn>QGHDBJ+n)>a&zDuk~-`;S9?i(K! ze)&f2j4c>MnNV(}mg^-r+yxrA52OzND|p6}KMQ=Px zlTc87N(PJtBXCzEBEl1sr-58x(@+4oA2=Gi(ZbIL?jiNp0@G0tGcEO>1kRQC!yp1a z8Tc94tidn9Hp!p0=yb$wuUqn2z}HI5+hIDWD#WJEXMjzc&jRCVhEa&uCC~hoS_Gy* zvV`gAq|BIn7I0rkmU^<}iKhaag}4dW%wR6?Y^nbRFdgj>o2U4!g$E8Q`A}fSep-ZM z0%EhIB^I7I2JtLJnT03Lko+ycW`X7bb6lkUy}-(7W^EeXy5cLGPgJx;cnK?h)R z^cMr0H7EjR2Gkn~Ovem}(XS1DoJD^;FwTO(Pm7rV1jhu^5Mh?|R$w~v#HOJtV6#Ar zf!T>zpnEO)#AcsZ9TQs6yPddrn%xu5`=jP{h=X6N0rAKwyH{NHjW!|d3~GP1sRP2> z7HaRdj=ls*=fQpg^1DQ=d_YT5FA*<2pbdmjAJkHV99=I$2c<$8Bp>1t^XhtB;uPRl zCH@Cwokiy(i_U3@nQ0R2(vBBt2T7a;yk26~=^hu(mQgYU9>EA};>{Mk%Yyev%mN*^ z@J$jwht^GnryUN8nHHR5!Gk1D;ngxj25KM|oQqJDCnTn!FD1@I#y?5ST5|AYW-QQj ziL-%cO3VwYN@5O6cS^hp@@e8A4jbWLVE~>+KbM$B<1o09_X4L%Or4PuGlMH7E(D%s z(b*_*U+{Y*E&~2Y;sLzBxc54Bql$|!apK0PuXdUPBKOVvtn7% zIR6X`13AVLF~fo%l9(CPTKM-QJ_vbS;xc9?u^kmlhBq_oYr(@MzBeD>DjDE#F-2ld z1Amg3Bl#kUdG7BP`k@c9CiqO!<5Sl9Pd`t@kuacK;H7Y>tW=-H`NPZ6FjS_Qw{DZ`Q zg1klIVc>6*n2W#LCFUaUVTn1UESH#dSrfrQRhG_M1tXlzLF^;mLW*&mVB<{D(z(;>QbmrZQ5G3M5aC*e&^f7X9ZDrxsHiT~+erh~4CozjCvT;M#t^ z#JoueO8ghdg%WcCd56TjskqC+Gt6$q^}mpqvrvu1YaySIn2TP9gG|7ijSVt_)7f(p za}~5z;@2Qww(#2|=9Kq_#9SR6keD|oA4$wUzZDf#N8$kYrR2c{jeuK5{3s)ShWyEr zn7_`kpsgT164Pj$#JquNBQb9_+DXhC7_Y>it6agr^)`64KS>7Mh`^~=N@W7x z%?y*6^J*>PR22ufnu^T+o@`i#1rT!fj{DQi5#)nydO!P`iCUu`s=WTKOylyAx~NO zvl81dekhiuQ;-DDH;uNCn0LOdEc{^>PLA`*k|#%Oj{i(UJKRH%Eir8#Wm?|1!4*oL z9I?B=82>OA$q3#;A48-%hU$tkK=R~>-I5<-(Latj^-5~va+N$eVz=ZQ5LU0E27bPl zI^@Q-#7&r6Mw|kn_N5Be$5M&hbaBsGJpcN$q)vnSv)Baciu)vW1{AT`9eH=AUJVki zM(U6wc1zw)ov{&}r=K*yX8#13gqK5f{V}{62A#qCoyk+6If$8JbWa1 za>V9&`bzTOL4G4KZ8lhNlf-2~lp>i%;pyOdiIk zNSuPn^G1pP06E9P&jU7QYCiZ_AR~xxmzas~vf!l>FN1v0!ZXaPln+f-S@;xIY;dGv z&zd|qV%a}}%JXIfGNS<+s)yWb;k`6;O~la0k|#&(mi$r4e*^iI#Oyc6C2oLBqn!y6 zJ0}eu=bt14ZW(b_Cg9^84W0#JOJp)}MI>>YY zWkeAoh~1MS3H~N|KHd6C;xmu~XjJMnN}gO}wCJ`$OYFzHPoBF$;E3J15qloV^WoPJ z+VDsCILVWX6ALzAaHI-Nlz}34PmZXLWU?s{+*9h1BX&!^zvOvOIEMPyMf3+ro*c1T z^2YFjym&7>I-)aJ;iG^FG68Rlua%g?z*ri^>XPmT$&({CSDm*={%3c1;xpRjHrS%n zW(V$^2Z+f#aLYVa9AfAdk@JRjxpulx-1dex48ND{MG$)@JM7fDVi(_~J8`poRLtCo z9dE}H@GxHZI$@9BhMm}5HcPxp+KY#CKZc6S;>8)VOGI=X*n}jk(!^(p*ylH-4)h)| zj&yH4SXD)FlbRqNtJ7LJ`XX#M62Ad0Bd8jCtBx~KUvZX+3?;F0q$@%6+oiPvJ#?3( zBg#v58Oo25ErP`q!{R}(MzF6qu}e#J%tuV2VLW>`^q&{~c54~f5;>W|BkqBSPMLt7 zkDlEV4Vx$YHmyCjeH~)VfJ{7J!W{%x9+_eRW1bf|*wckQU-|!P&)16QY`6X9=b~aU zb))T?P~ZLo!k$gGSk>HQmb)2&S)zEeEyM97aw##&TDjR)hAevKdo9kgtqfake=m!u z4YsRAeS6yySU<7BmI}iQQfwLOlcL`H$ z<4JNkHeDiB}<_=V54Hg0>Ifis^1#v5w0yP`z$!B8~PW<8B5u&qHi#qEr%W!j1G;o;hR&Fqx3Mxyz* zhy^3j{NEynDB;hsC5UY!wF1YF2=_JGJN61Re|L<|j~T%US7>FTCjWd-{jUuYfgTs^ z%(qnQ-yS4pK4)u}^sj~pqle`6=ou(9dPrJ$=yb<`Hf`dE1m0BxHoIPP7Q5^`TKWjB zw5wPfbc{#0byPYuRoyS57C4r~9q3Z{SmL5CzLKVLEq_W6&ACpjUEt`Gsiph;*dCFR zsbkNeo*Te^nf^_++%J=+d%7=~qj#_kJffA}D_Sgc^i~&%0Sg^IRTEPdI&$00_mo7B z(tREJwNg7W4fYBwZ70?*bX+?aI}uut@*Qmq=))5ixfiC!C1$z<`t;GCYo%S3OkLlv z>Y9BDHbXZW+2DoN$^~&ekC?6a(Me6CRO6=RNv3oF?NW-;+GmT?E!6RV!T#f6AJh`V0%oN zUa5Y-$UWPKuW$5}1ROoRsb2k(p8j>B)$NWPb(iROyQ97RyT+2FRfN-C` zIC7(d?a;lr9(Wm70-zEF{|W~vNb(7ISnP$=;q!rWB(4C)Ol|PnWr1^F_Ny9DBpZ9&s#>Qj@}edBTyDrLGA-w#N~# z2ARbi)H|U=UB_3!8M5rv$c5M)0)U%mso!lDe7nSV zLEd5EmrBg`deFi@09)#PhDqfu$&({?-zOioye}h8Lw;t#%b0j}B=JeflOuLZemQkm zdbmcZLyp)jd8ce-cH$bunYV+T9JqxuS`TC=M4I=5tEsdU2e@uBF*#zl%9GZc6gxh~1JOZqc72@w_1b#t%I_g}`^q2wo-|U_fPC!QCf$a>Q=QKPh>19c6v^ zrS}|7@!FY-#9zO548zMCExy5wSR}5b*dU&wI4XXo@QO>ng(wscQP+@i0ZQ_?lvp=yd{OzPR&*V+01PLnqK(9}wzEyy$arI}8Gm<;O|P-Gjw& zvR8nO6>1+XAr`;5@Y>+0LN{5gq{2<-k{xEUN^t^gL?nsa9}TMb$MaNWgu0*9z2YT` zYVjF_qZ*dvyIkH=NViA$Pl2|#H`hV4$X1I5VA0r5QS27`Ae^~bxEFSb*AA*WRwTZE zAX##6^ljrk6|Cegd@sf_&l<~z*g@Kv-wf2o@*z3==S#I*V>K5SdbU4b;3?yKJ-OlW zgSD16b6GKe7?u@wF}y35DXW1UykCwo+H%h@F69uMX9QC&NAMK{w;Dm?&7Jv|YgldO z`Tx~gAToRVd*$XEv-h#^OWkZ!9l;ix_G(2%r@rl+@w^8U=1-h3Jz8B4Whmw$^+yIX z`4QfGy~D6oCw2p*}3{Z3o_y+_k3;Kb)KdAko)yvH_VArzs%5_{nUw3w*66B z<&@SFW_lGI>;35+G-rY8d%Y=B)A!p>Y7=y=BCA;6)p&4@@8uxapRoIUfa-gxsrV&? zl8#(fRiu82HzK;I{nWvkf1G{iCiN}WCGgy*^JXvJRIpGhO;x?#xw2HdemOqJ_ms2~ zP<`tRBU)*9wRl~Ve@&C8M17gbXGS}_s$c5ueJiAHoa$R1Y$|@7`q=l528>oqqFQ*I zm1(U@qN3*PI_(|c&2bjxESfcQ(S-f6_4RW%jPunpw zPIY+wu>{F7*0uL7l9~Ne@hxa7u8QP^H$3W2D(e?}5`&3$XSOC=)=}D8$%*QxUV8tP z3yf-4)7qf>$1GsI)3)d+S-9I?zEhpm z-9JmOeP34w_ISqQ)ICe4Y;W(I5GhL40mV1Isd%zcl%VFEq?Fbx2XFCRDWi`lzR^v^ z;~9PAD(9!lml^GS<&ijNo#HENDjs7b)vB&g>b5DXqEt_GWtY~gqLjd{M(@*j?ZXo{ zG`gmIQEthifsSlne`$A*;wv_cYISca#r>Q77o)*~(^jfivPx4|R=uHMN1C>_zlzj3 zi;DKgE`P?CFEf5p@dcWS`$RIXdsL}=Lg~6VvA5l`N*{8!K5XjH=yB1dEzx?tD%g6{ zR^GYkso|03@}T<{Zz`-9v*5|$Q&-}I4qhDCai;whYvW_q_4u17=%~|_p)EaaN^u!E z5^b5DERQ>B>NH~`IjzMd~r?1DF|iUIkE0`1^vA;qxGC9#e0ia-_e-3 zIeOiycD|^HcHMl%=V~gBGqm$d|A>06in1YFqnR|c(csM5yISAzgx425(`Z}(rLz>@ zFMt_$YE?6pVtbSSXRLrr2Pl@47sLYPN>LNYM~UfYavtK9ZocLMi^a(SN)# zC(2oumQR+V%k*;(SmZ!$`ofvc$7H>$s z%~d>c`jBdU*i27{DvxsAbveGU%%rR0dqHNBsT9A_=-+}&)O|+b`r&6fTNN7jP%AOX z>wB$H*Akb{(LL46bq-7H7M_WbVakbzSe}v$d&}7?8Uq<4mc*CZl{+T2&^^KGB>}wA zrz)c-xjf~OM7rnhDNEb=9zwn^26B84GXII4i`O;!AHX@mi0i+n@nq_V#2eN0lD5UG z8vXY*>NTqR3=8Fnu1iviS2U)V9NUxbiQCZGce`OG(YMGj6H~mb(Z2}#_Q-oiJus;> zHR(g{(}&I2KcsrU(F88kEAek9=M|4C__}mMlj2GA*gb6y*#|zZmA=zd`g4;wbG_C+ zyt=u))F;50d;T3s0N| zo*5BDVZ)8n6=U2M*`DPhuEymR0~hcpNFacn1v@cPtR%# zPt4mo>emM?5%s{`WJDt{3&V^R`}zI8xxnO@xDc3*VPgJ1z%f5y%FKqrmgbGcAWSnlpcE>~88n663cf2s{mO3@o?c zF&5070H)3)3!ZMlf3e{EEcopR?r98~@5l%ato0Ie&}5fWWr2=Lp4?G!&tiL0%&(H- z;P9&=hTULGjBbfWV40G^wG7X`!Sy7X9Ze`kOUA4ME1)Nbpw~!Ir4CBzW7B;2nu`q5pS@ znZX&0z6)cfS(!MAz0l{VPo6EoPdE_w4kEKc8DMStOU&BfdjW=0KJajfnb~BCmqI=w z@l%j1C0+{|mY6oTOH7+PB`yTs3mjxAX!Hw9f(A>1A0_UK1iwm5{UltEOv?;(iJ3u; z#6`fICCnQ4koYpB9V9W*29*&qz{KMv9spb+F`H|O#7umz#LW0%iJ5k_#Djp>NzAm* zOU&Vkvx-^hcMXj5&%~d|h#|nANzBAwO8f~jHXg^J#&mqtW*RacwSlLdc<7NY15T8f zcG^lzJLwX0cFE?nVj3!tn1)Iu9tnJj#5BY=E~wAijFOm!u927n(tL?I)%-<(h2~U6 z{YlWl^mO&PjJa={5zN>DMdGQzQ4%xbM2R_nWk^h;`4V$=P%3eEr?{cgrenCfztWZj z@l+*#(k&EwDUOO0m9{>e*^wv8L5Zu)X%gQEIYZ(?F?@k7DabKv7K)&j;{dl%Mw25p zw`|i4i_S$V-XAwG$I@jIGs`C==2*H`Vz%$w5_2KDUt*4{@2R*>Xq1IGBqKP;9+sH= zTolAC+_#b^M{E}EXUTI#tjZyaW3OFe7Os`V9DCy=&b8w@Ns)m{$a%~RlCDtl<|Cu<5+H<|WNJen^eYeD%0q&KUHF#KJ z&H&3L=1{~mY(*~7pOTof!3K#r@P{SlU`;*hbLk%3DFbgq?v|LDy(=+igZCw7W<$+|4$ee>aF^1UT)mS$G5Spv1iS;Iu=YYslv%=Dox# z5_1}QU1ApKEs5D$pGwSIfFlxf#rKWG4ZK15P6n9xw8X{~14U-cn~xNUIVE+HnEDwK zb9(Ax;rmI*Sd5l2uZUYDPmb7)zQ8NuZprhm zCnPbau!kh3ofQ&uI$L?34=PKTK{*a^&&mjL#AcshE!YxSFtkHrj)^-hc(25q|LP@X z#ve-j3FOBX{s#l&{PULSR~eB4Y=dWJOdKsS=f7AB&w@~gcU69gInCuu%(Q(a=9G7_ zg|9~C%nDy-&XXj$3NUNTxsMs}mTa;GPq*NO67%-V__Yc8#Pm$d+p~u(m|^mqKi5kf zovzrC^%m33GqbXVT*0oN2x7D zxhLv+(fNMcJk>2$+;79T3Ps{l+d4H`ytdTVN8BG1H7`6nWLs`iTZtH9`xSS6EtlB_ ziaTGm_f_M<_b#)=+oMqxx{qg% zsnNW{ggb@XSA5TJ*yFaO1U_VfONLcd;0TxBM6+%0jB-TD%arcC7bQxmuBD;r{ zi|F;(KbIHi^)I$h-HXjdYJRBOm@ew1aEA`Il;3XZ8Y!Btwnv3)I@wOy#NRcwv+-F& zfzKLVgkJ=!MaOS&D!3CZT$g66a^m;Zp`kqu`RPXNUQ4$1?9r3ICTg{pgjc<(HO6W$Xkx`j*h{tb zBduq!_Umn*ecQA!KKkcPS;c2<<*RQS8sq7&uPu7>v%l}Vb9jpr>UVr-zwPs;Lt3V1 z@$eT*+W9`iZwVhvj4M9ev2uvMw$wJC*4vzb5*{ zlD5A0j1;Yl-*56CXll68tJgTxzcWG5V=Gx(gsBnI$n>^&yG(LMIL0d?ocpVA>}~Y`&6uTZ9i9@7PvJrR9*B@M-`D zxQF1Gm>jWN@*5@3%(hx^Hn5p?m*mM2n`v{Y(+dZ<1AKzZ3`ib;cgu);VDnwoPl2gJ zj@W!x^$W?f_JzRa8=5~zo*c3Hf+jz5MLX0_Ffq@6jtmTi>|w!uX;jvDpybIBo3+8G z!3?A9|{k;Tq*$&(`VpVlP*D- zx*L<2BL!D@YUFFZ*amySmgyI_*ou6=^Ap>B2W$so@txE-V|R4;{V!|}4KZh%$^bTG z4-)qW@O9KmA8H=ij1s`tQ8Pu0JnYXtD6Y)I{_G`Jp5OJ#Peq4cz0%dxrOh)*dQP#x zuc~7eJtz0H-q2tlbz^wn?XGs}Wu1JFVzj(&Vp3*y@xx8nr&+Gq{nbsLQP_I$1c$-Q zY|jYL0en5HhGGBxO}edmdBCHok1_1AdvoXJ*wsfxVU=rgXnU_Nzp332ap+sj$EkO? zPA9bd7|o=^Cuw5arCRUsHOpOk3oXAOvi&g7OKwOE6#6CO&lNk@xZV*S2Zpqk-(oNO zMGj8gYhAsg)%9WZdDn=tUPsw6x<;{0Kk!2?MD zlC(iQ7V+x!IKaIld2+;V$xlF7U4sMMCsJpE#BRxdBYBo(65>==AMSg}lLHo?I-}Y| z|0>C;Ab$<3uBaVZYEtAKj}LRB3e`JAYkw5Jca6cNmC*&t{86#$dQn04HL!7!ZcMgb zYyzw9qev1Br1l9laGoj(7}W4U)CjYmZ3X3s%`sPXhp910oCri+j*V=^c@T5O{drON z3U6MIz`t0YMRq?G2J(#cO8iJpE107=jPdO3Ro)5@e9XDV9=fF_I@GYTtB7subcjn= zIpfrC#n@HO5$eZc<0@xnjD&Vt4db(X}H)M*{?Il*Lq@2&CpiUGd%sv zS6(!+!l}L}#y#O|f9ZtomFja$T~bryv0(-93wGQ8p2&RQ* z*Tjc5_G%-%Yn(aiV`A7E>>pY${`-sTGvqU9gi6P zg0mqSMvNRi0GZ)oFFId#hr4ZeZfO~g+UvZ|DWaA;CW^J|Tn(YdU#nYl-EiL7lu9x1 zDOV?P^HZ)^F=Yb|RXjYz;EO=Pd(SHa+0NBHLfe$3&Eg+u7Ur_!ytCmOB35Tp9DF zk5c%VMuu@mkN7dhlWm4EFd%%DGE&Az!efq5 zBmQ<}0m5m(KBItD#&g3Igx@ma7aNZRY0nRj-z)AiegmU{NUJSTPBqJbkMfw{3ivqX zUZn%VEHDcfhXLkd8SZF=mnzpteGZjzc#_D^{ZK#BA`dBR5N3YpHbE#XQ{K8D!6V8K z7bIA +&I%dkx^3Xscd>jUxzA_x?cQwk@7lcPoJ}g_GiRjWdc6j zi&NGrAIoqggC~vRGeg!QPI=ncs~~HD@CKz9A{fRKDuka^uB4)Lv_DP zuPT#eI4g3gzixcYjRxp>H@_STEQ5J>zb5>}XU-LN@%WccJ-qKrr`-{K7oy>qB0&{5 zG&qyQ&)+&dZLPfJdc$+9j>nxz5Iv7OySJ6|4hyJ;XeW}Nx>VdottH~21zXF*CuW~UCw*{X1LdVh*$_WCIk)Xm%%Jv(g+=)W>mv z2z%yoXO&k4Ni~R(jf4}pPlhi+LBJS_DK%(zsGZy z`#ru@B%8fvHsVBsGcA%~TqLU338yDQBt(d5=ZM4z@h}MUf?*zL!ObU}sr@!aGUP*# zgyhH-K;^I;O3 z#k_vLkMKc*WWcNpCS zLx8cr4oc*R-EwFsq|P!N;5N&|Tub-_-GIgd z!^Ei;-WWin4hDEb->8+uUPyYTWktG6TqqVCcP5w@`o&~v7H%Lsv49*RF{^@hG5CB{ zQLdL5!kCs#{dtn7{+$wE19_js5XO{EecB1u$OtAd=3+!J0h`P$&<=@NpxqKv|6_@% ze^O!^ZIT#5;U-%%Gv0O+Gi^!)2dQH$>KQQ=xCEYae*?_KUCYcXxLO9N^n%1xdR1ZwB~NU0B{>K5l{`6O za}Hp7*bExm_^yyj>{C}+F#C-;nXpA!2y(=xp;?lD0P>F#FM+(xf{kt^3sfa}a#cp3 zlo2$*4A{ROlXxTKDhpSE*8HrB=XCKhib&0)kS5<3K(Q6%7VMFRfaB7y&3i_|S*(_@LUBvMqkMz75UEq3BYZ{>;`8- zMZSdvX0hm0ULbHr-FXp7cLCqiWTF3I1RGtt;5>GJXmo>EUO#ZH;1hrojLg+uMr7yS zMx1d_KZ#&gCxPQJ9I^Y8h-yEBF%B2pPF-Z>AAHT#U3|R=ziPD|DMqc#H*4vS4m3 zGWF+M@L~&oz=CTmc!LE8`3+>#&>I$9Z@~vG_?QKsvS5C#*tFxZ;A9Ktb2C#XmpDxk zU87ySgK3dQ;0J-h8SZuquC`!4Ix}^iwBYA0xYmOASn!7yeAI&D8Z3b`1{Oa>yKYf4 z#0@d7KAkfnMS7(rvX*$a1s^c5cqhj71IESITA`cdi0@muu2;K@t70MiqAnI>K>S3J zC(>KH)~P+kJFO8a5RDXtqFWp^dy7Zn5b7h|igTq#%L|2<7rOW_pwxb%V>}ct62mAi z7PnCpiDxNFLZ7YdX6%%hmEbD0vrWvbH+tUeeKuSLYS5rqj|qwFH#MOYmmTE7UZb0T6zMASvZ_YsjS z)G$;okBC1SLezxSGWBGHYA=enLgCVgxGp08BK#d({14O%D0Ja}2`WP(;%16Yp~JUC z@!wB(bY*A@TZUd6o{mR9+YrjS1LuT;Tv6oIDK$eQ69DIm{_u?B0Q8b*-N}{F<@sjn zTP^CBSk#ZT6canS(z8BqreAN-A866@;H>Z1@g z)hCJ;I@I|IU#ohyMSYA#JtVHA`n}E62UygvvZ&XIr=Z?tTQl{s7WJ_f^-~`4i_W?> z)1Pb6A8*l56_=)>G##TaEc_Cvr$LP^Kf$72CLX3bKT~V1>qe+^*+TV+7WLc2zSpp6 z`b?@TA?uIL(j2ywXp$w(2GJ`G6<*g&{j^1WibegiXmM8>Dtxe+e(Z?zXKSiOKVJMD z=Eb1b)!4R~7M2ZQb1nMm;w6~R@?k)? z)-}zdezQe=jA)VJ%IG(unR;J~Ix9g_=z+?eoF^c$crn}oMC>wl%k{gxnTe4wF<*`i ze}b}UVr4TE%VDcCw~qH)-poQhuF5o|WDCx>Sa_?Mg*RX!hZZ{QY-ZsUESUZHHu2pK zwY}pMlrxN->fSfh*qpS{k(+nsQEADeW9)?$O~HEVMx&H%5yQF^!P8BEh2@a6un^v? z=Vi?-EP;jIhJ{O-SvUg=?0>XyyT!unW)`^ayCl-sGn$#0iV>+sHg=W8#Ij~4VzKi0 z(kMiznT4pU@t|5-SZuMdt(k?>u+Y!2@Jcfax#J>Z3#)OL#lqLkEbyNJv^6XoZDyew z7SfQC7M55n#J0ZhWQ>G`3d4dMG1imuJS;pZE!=Cd(6gC^t+0@6SnxNqFcza}uC!2X zv2blO3-z#&Zde%K%)$~_7$hw$wOF{fnT6A^P+(ZNvzdhhurNVdc)()e)n*oQ-MH^H zENpFNA^)25-TEPmg>RZ!7z+zAhJ`PhS(pV2=J>MAVxe8!h38@hEEI^@qg@Go5o0|U zi(z2`Qu1u_fe_<3hFsRn!s>IixTKkdW0qR*5;HB#Yi6My7TSsXulQ{l(k7hmQ7bGK zRyDJ592TO*i8hYk)M5}UnC(zwv9PC^g)_9kmh82wSuG}5EUdCvINi*GM|}3ZBdOny z&63YUa(2YG;a6Ld`{OS>5&RcpNn&<68UZoZ6A@K$z7f`1ER1VrVFE0)GdjbVW)`w7 z7I=A?C*q!F7Usi(NBC-NzbQi*ESSysw8g@PW)>F1LZm~kYgUG-77H6J77jME!2f#C z-l)X~%`8+}YVoYaf-B*|mgK)ahzw8~VyrE>+G1g&#X>Q6=BTWhAWID zj{|KzIYTVTUxlLCN&7cTUM3a0krxbFZ$uPk`g3lDn9UU1WeSsjA1NA)_r7Mn ziYRMK%tuv@p#U5*>fp_m_**j*byzMnz?+VZO!rnZdy^(d^k{Fl@e+gc#ZI`DYh!$d zGrGD526`+{_aOQ%<1GefLx2AFNb%ZcTS{!jtZBdfkoT6Yw=U`Zo9)8`#3k4WY`lVJ z*+k5b(rS{6Vpvv!}zI0IKZuEkG_5T658+}Xmm@|&wlybrLrn9O?74s%yg4XC0^1Al{(s(^QMmS5tda;>8Ml^;%O48F1nOfUiwc zp?+4wXTZyC_VmtOeDQd9c=2OH zU~rC_L0aGIRnrZSldGl?1afk7Y|(1!gDssy27S|L%_Y-!Onz|gE6D36#vqq38~e4) zajMP>^MHAqG+(>hr>YOGaCVCOrBRxXR!27bFS+rC>H?7O?K`aOxv z6umgj_j;qQ4_~sdFtDV*u6C`pDe5ss;xnmVQ6}oX;#V8-kIngwywAxvD>1kn5xrGs zDgFV&0@c~AcqjSACl=1^Scip}@BYTw)hKxD=>#l88T;AwO z9H-$ts#S)8Zl3taN%Uyj_cVAC3b)mkgwR=nj6L#+s>j@w9&o2m#4|23Rc@tl8@_+o zKbij$&ezYVZhK!}qq_0KiyDjD6gA%3VrEpo7`)^&i%E>5xb1Og*YH%Ev&s?NUeSB6 zmf1g0kycWX8PJvDhnkL56lxWH_E+>eSy7OC_=SNsduE*X*eSdZ7(9p_FC;z6Zk20>o zo4;p{Z*G(NFhgHG7o+DW-W>Qz|;^6&cmD5*p6NCXR9Vu4&S>p58M1s0Z!q z(?wKEXYr6i+miUI0$avRttwN|op#qmtu$THpIhQR6sy-PPH|*B7Bi*5p*uTP;evA} zd&}~5U&g{j_o&Sd{khyO-A4r+)$iK_b;)|2z-4z);e7A zHc%ai*X{^ubuqSDy?SA}R_;_&7L}DH=sVA*eBm7t3OI$^?aT~jMyD^<>dt5jeVz9t z*Zrc6epV~}Sxe8*>i((CajHW!?=7(#k^;Uod~euOUg4iuk*juPiyYF*eg28QTr|Tw zTGeqFNV_UMtMHJk?kx?w+H|Cd>E~2^)YU7}_Qcg~*8;xILp6NGxC6;4aa!Fc-L!)_ z{#d*kc6WMQ%i@Mce?y}u&RMKheyYCTLBoedbuB(|p^E%#v%PrF|Crm^(Qo|M0MEj@ zJzB~foEGQiriH!?Pu#4`Mfe!+s8!$ke`>_LW{GGpw(k|FYJtbu@p5OfXHiC8x4_E# zGDc)#eEgAJ*#A~zL0r4yqxceLi-7(9j8F{n(rXm;IAceZe^I_IR?ogTuydAb{6~S3 znpqy3zAaY$QmpnkuhB|p{eNYh378bc`G== zmFef7ex8|n>sMcWRb72dS9MQykjVG@cY6}^yn^@ZmQ(~S*QfgFAIqOVQ$M}cTek<} z^8KFu8%S4+>HjsSF}cx#>-!EW&dX$G9`A)Gi%jZxj=fmb4MAPLKj@^pus^W#^S^uP z!j%UyN}I6qEV-pwHLbF@ne@-^Z$9#Q(VCv4C&iT@`S6(~I#)F1`-6|Z$qLjansR5G z)VP+aML~6e{{J%}m{;KUm_N2EeRw`dG=} z>kl7a;w>O4Q&ygC<@bF%UVBV@X1^Atru)RJtCyyaE~pyblHRvj|BcpE)qQs*()F{` zXBWJ5poH_@1;LR5|3q(SFrd&sWl(Qznwv89&FOtD!{c#3tsj-1K_))>RWF_2bK=H5 z-7~>mOEdXB`aBpPeb8$RHWvCNZN6)+{!Ke?K(MFK@1E{$E7mE#tUBSP%Ss0f^-^eg zLo)R{w0HFknhX8m*#pg*taPwfMAE(kt=WGH;EKN~L1uYGv=W)SJ|L|f(MBG7>oYjs zxI@+PhR+&Y^;UDbb=~`Q{Zr33=jO-V=A{k@=c*aDdR5OhS3KH0ofG0W&E&sR`K#4V z&-KWboUrHPb5eVA*%~)%;^|yAf0I|WySd_b&C2v?nCW(}(}l6>7j{iq+Gb{Bb9H_5 zS^iCxrxnc^HE&i~k3N0kwLkM#Zfu@jSlw^ZlG64%0=1dGWY2ROU&MS_MZ(lO1B-bvlP}u9^M_=QO_Z#o|PA&1IN9xe= zjtwSu@Y6@V*_2MlrtBM_f$rrU{EBId^fr+6bFFpWtDBkeTH{>Da9t`h<)uDV&o$+B z%Cufva(zj8?QJW{msaO{om#cdyzp&#A5KJ%R?nS%oJyHrM5Ix-5(6;==UyJ)#Sa|q;hJP>PPtQrt0`wRlU=$#N1ia($5{Gw*Xw-(eI%@ zWo}T=RqBdhKqtT7pe^`gZLiOt-cG0Ud~Kn6 zw8n~9y1?t69e#e1Jz&at4Ygmkq>6*?oqe5>8b)^ZJGAnSx^3?X1ODeaeN@8>-TZgs*>p_% zsy;jP+o(e`?9DwOKFRct#lwwzsjuX0O2za!$;(_$Ec66njrN54(1;EnWBMd<_*1MW zNMh$G;vAi82{@WAKEX0DH&Zv`9by)2U|ouZg*_b6;fqXXmL%stEk4$CW;tR?x6o0g zA~=fcGfvDx0kFpYLfuVDi_Sbg&gra(J**+B(0*w|hucV}wSFvit+<>imAYDn+anp^ z?xydE=&(ix!UCQYJ4a86M@grEcBvC+hBG{3cHACG=&4 zOZ)-xt{cU1eVBrj1qbl(U|rf@#XCtu^YX}U09Tp5IHJS-q~nRHzdD=E|KGJvHT?_O zxT<|AzR~httwv{2RkAT6ZXdl(>@utq_mELqpPga~rS7}L8cGQD{So^=i8H1*iQPfd zMUBWpUYNlVe2o=)%VI=3YM(kRBnV2y-D#6>`-NCV1jK+umjp2|2wu?DXi0>C` zI3=`sRm_47+*cuan`;#LfkjSIs$2V!VwD{_swS5f0vP9H9wqK=e2Ms|;K)+F$a0WL z{CkXr0Crn?hu9VKfcRXc<1(oOnGpMYG1Ve|MnoSkE;W6zSOYX+Rd@+Ci}Ge;M2M4l zwP1|Gv_3D0UBNGkwUI*o&*Cn|pNLtg1ng`+7rV-RDRzg{cVg$0Ln4ne6NY(;u;2(j zP9gfxhz`45Z-Ur4nkc5ie3nG)VYkLBB0B6gR&6$tP%Cz8aC1b5-G2Cp*cHr^I#pJ1 zvzQ9A0^f-TDkNUUs%t@qOB7Pk8q>ow6A^bly+G_7%@C(7!%EA5BbYV7(N7}wKNYjD zl7ENTRrCR|+pJ%U%Pemx?eC0wYmeJx36G0iC3sAs%AE4jT^1?O%pp_O!jIJ`~66+_% z{p7SRVsoD{*Liy*I&mt*Zt#q;qOpUv36CBg<@ag_Vtt!IFb5+a=xr3AA z1zK*<$4!tN&gm{2v`xYIGxf0jR@*aIOM;UV1X^~RPFJbX_-%#HM|h3wJo-^uUN;>L zPMZEt(>t}!-PHC*gyyku_V>2>fB#y=i6kvyo#M`@$ugrgwF(L*_?_|-azt}(kd_E4 zCTJasOxi37cB{@j5t!1g;{(%`D>ELdkhvq!>Asz5%#k_Ym|ofv<24GeiEzEj)A|on zpq{%W)Em17*rK>wpABY%wjpSy?psW{M-uFsVVmh(zVo4u^Z@r6b1-kmb&bBXJZU-_ zoHTuh;-2ja%xi%kG+6D_UucumD}f&4F2%ixp&a|vGN64LJT_5((f-b)ha|yCGcB@1 zke+FW2tSIuNjZ06nu)7T=er5hVP3MPZghII%g)*u%Tx<&v>cA%Z!&RTxrZ%>;_}1wI;{e@RW9o zCE)Z9W4g7!Hs+MJ)tJ-XHe(zeVExX}mzHpnd{qbyPMRK01T39y@T-=$Md6!?F}XD$ z@}e@ihWeKop}}rl1f2A5*-w;5yUMV6|-SYJ}4)88}bZ8*}o%+n67PdyUy#j~Fum@PzT33ZISe5el|5 z;9pEfgWZ<+lJeb*jQ=vDFJ%O~85!d$kjgQ_kcjZt6fjv|TH2b92D`ZsQ>Iht<09N7 zyRdRaf)gzP@x;KJ>~}84o-(U45lm=gbd@2O4v&8eZJUO})(LnBGs!OzF5U6JKV0r7r)% z3DBjNOAoJe#9Zk$noYg*BgS#Ty9(=KH0cl zJlhyQR~SzeZ#9mqg&5hu5B4v^Sw+@sbGFmRC5$lU>i-mDMlASe5H{y1GyevHX`x?7 z_&#GgU@sd}p^uHHiJ9ES<;`}rNWBu$#^;L%8qW}qFrFNNi>8CKpzP1^EC1(F}mHvZq1v?SFdY7=z82wq}XT*n% z&k0t})>K856TXs0<-Dz*qQBGq5g!U3o2_dHet_E8kIiKYJ4JYl*4vw@FD*SxM}w25 z-=ny*Iniv;U}tlx>HM&5kJyim>!P2!AS&{G1`N?>D4c4{cz*Z>8tKOcKfTx=qx*OV zFV>7%2ZIkU_J8CZ3TDnx>`-v^9RJyTR{J&jJu=@BOq#2XAkup#{X^jg#)pEHF8MQ) zzEb$*_sI{;^~YrSncYL>XX{JLiQ3*c-(#FK{Z!M(Dhyv(A{&O8o|K(8RbN^rm<<}7 zG<~w^=P8_KOsy5q{rqxw;v!3cml|`Y;@Sv5Bgfvw6lFasRRXP6Hc8XhMeOOGu`=w? z2W02XA!jW18`BSPkwqkF2|F#}A%(v;Ua1CqBEkoZ2PAYZi11s+Tv)ts%s|Q~5u1NU zIP5FUQ|)l{qH5*M4J#LGtvIztgOjG`n~r_g2){z!dAYn?6O$JWPMY2?c;gaXzz?zH zzbJV~;LX>OQf<=flHlb0oF_U%c$%(|`+zX_T8P8z6wWZ7qwpeQHf-2gk_|VAE;W6T z!i5nV;_{OXueGkQ1cv*$Sx5o&tgegbHyLw1_A_G!Km%i5pR&oAn>pd@RODxuw0hI; zR(O{&gP!+>gH{{FuT&8uLrE$C!)1CyY74A6BDzvvMu>yy<9g()6%r zCR@5XADK-TUc`6ABLAoGE8`}G-x+h|_$~!pnk%4<;}HYfW;*sCMC`*pn(WcS zKAQQNAiMDQmwRPlZ%an-$7Hrz&rqDg&|tSVb49_jY z{&d$UfF0*c8F~xJs%>dH8k{u!F4ON(_#0#L{?_;bg};mFj~P$XKCvglU(2sIi|ZdP z&szc_?AG$NNQO@%%-_bSG)}{zJu%nl-Sk0+!=XLnCi!(8>;7hg)<3v)p$@{~Cef*a zlcy+6OKZiw%W`~{*`UEm(=RZc%m10iv`5yM8=lOU1eRVlyZ&0K||elD!ktq zM~@iqRk+)jyN`{=+!g(YakIj&BK(apep)FH{^@G?##}mdY^(A~=&neYNJ0thXpNL>zWOE&#*ekt94&v07(H(Ml)`<+U*`wMFY-HO=|3`015W6` zFyWRrCRgZdrlY}0(@U@!k+XTvY|vmgpjnEI?et%m4I1nYhJKpd{%?!?c3C>IR6s%u zc1Hqhg?_X`{@Dn#)}4&UE9@EJzQ%Ml`x|4QF{ax&G@_SL$>DaiR9gZf>;`V8n9i;A z>BjU&XBbn!JY)K%mqv76Y~lun7|&n@&|v33+s=*_`m8sa5%Mx+j`4>I-!tB#iW0{j8#+sH zLLAq}>3xiA6iyCV?N1MUnkCSAT5r5r;YMQ~h4_^*w@0@c(=*=|(f1kC$$H9|Rvf|h zUYt8@Up5`><*Xt}OZbN+@FYRAF%J*4(uXyGN8;#*IY&pCjs_=9FN)Y#V!tG3-`#XH zI4Pa|FE-2)mMI(&;gcgg3P)Gu995c*1}9A)9kCya{nDKM>87K>Nz-d|5;||0-!6Zu z8Aymt4HhrcSomy{CQ5>nSLS@3gWn(J_;RyBgOjFD!{(}-O|99W)dp|Kb^cb9&X=?` z@UGM~!yinVAqh@ioy+~S=?siK7vYzU|Elm+V;-@XP082f@_uSM8k{tpzX-B9*)NjH zBhH4SE(N(rn9w=G^Kg1{&S^K((cq-%eN7*zu)i?{oMOy_A=ME+En>5P$yD7X>baJ% zKn1|=;%!bO!?ngdJo3{B-)u}vETYo3#&?;H2D_HH*YraSoREoTVc6&qmmr-&&>2$N zZ_E(V0b|zkkTF9@uNgBw`L6Lt3g0)zekql+U(|1KFo_^^a;qnMC$ItT6Pc}Bp5)k2JE+NJk7L}mZ6C%8V%+|cKO-F-W z^ImQ`kJnsh%ox}W5v~ha+n)k{X$cI7-DS*UH1`|xJkCQAekZ~=P@!vct@63)XmHZ> zZ%wDH)!1K`v-jP=8KSSmq$P9^v-aH-b~YySvBo^V(o@rNFK5txgWuO@hJ|kmgCA`0)82t#rliEKlz!`S zxiKsW9zZ=JbyV&ppGT1A1>Q!?GnC^ z=`iYs;4`TTsy1ng{_;(dHoh_@G4yoI}w_PMPjN1FoHW2?n$+`D+?jci2a8Q}_n$Lfex4yT|RzdI0ey>D_o5Ary zz4mnRX4zB*8wp~;-pziOu0zTPmqeC|VVR1-nTp{f${X~jSpR=t$2lsv`CaWWC5zg$ z4&N5k@NM_R$E||b<6g1e;!+g!;7y#}N)p9M_ut>j0f{2->tND=MBhZY##&3l23R{F dF(NTh(MNM{$~;UwueBat3*V&~RF)+w{{yAUcl!VU diff --git a/components/esp8266/lib/libpp.a b/components/esp8266/lib/libpp.a index aa59f60fd5f95b5d2039d38664bd642a2c66c5c7..143e90d2eb7d0377b5574186392c3d1432ceb185 100755 GIT binary patch delta 30636 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%0Dw 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 From a977a9d24fdc090fce1abf8d35ca8bde2587e9b2 Mon Sep 17 00:00:00 2001 From: Zhang Jun Hao Date: Wed, 2 Jun 2021 15:58:00 +0800 Subject: [PATCH 17/57] fix(smartconfig): add timeout for airkiss sync --- components/esp8266/lib/VERSION | 2 +- components/esp8266/lib/libsmartconfig.a | Bin 158922 -> 157626 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index 6f12cd1ad..e9a581b6b 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -4,5 +4,5 @@ gwen: pp: 231e0e2 espnow: 231e0e2 - smartconfig: 3.0.0/5f550c40 + smartconfig: 3.0.0/4d91b289 phy: 1163.0 diff --git a/components/esp8266/lib/libsmartconfig.a b/components/esp8266/lib/libsmartconfig.a index ab3ccef63b505f3d2dadc8b764cb6531500762c0..fe851642022dd8b5edd0731086b876cf0f4c124d 100755 GIT binary patch literal 157626 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 z\n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