From c64cf2c2bdc57f5565e53418adf379811ccf2db6 Mon Sep 17 00:00:00 2001 From: taisirhassan Date: Tue, 28 Jan 2025 19:17:30 -0500 Subject: [PATCH 1/9] PPS Handler Diagram PDF --- ...ipheral Pin Select Implementation Guide.pdf | Bin 0 -> 193994 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/PIC18F26K83 Peripheral Pin Select Implementation Guide.pdf diff --git a/doc/PIC18F26K83 Peripheral Pin Select Implementation Guide.pdf b/doc/PIC18F26K83 Peripheral Pin Select Implementation Guide.pdf new file mode 100644 index 0000000000000000000000000000000000000000..45c02cdd96bef5e071f4281c0e3b04faaadd7a38 GIT binary patch literal 193994 zcmeFZby(GT*FLJlD2fUw3PW!dL~_$1X&@je2uMpyOE+6o1O!RxGU${BDMdP^8>FSX zW1sbPoM)V8p7+Fc-rse8@41G*W;VF@cYk87d)@cF7OmW^+ste%oOrYyb2FoOY$#Tg zg^n?vfB^cQk&UT7>Z+W?O*Y=!?A(&P94I+`E2Bpb^{uo`QF2D+CGGpW5M2T5g7{VLhve30g z$?Kcz>09Yr(F+OT!G9v3%<<H4=KmUmL&p(nuap0kE8=2a` zC!uefYTM}F($}@n)5k+g>6;tcJVdecaSI8dtZl6HwaxGxqFn>Z?tFf5{yDYD_4C!& zJ@N5LDbza;A7VZxWZYL*^H56Sl=kV33rPHS?Az4W*()r=kH6_(J%K;=mDcNZt_2y* zv6SiMDQAbZAoR2d&2t7aPnjO;#)Kz#Gbn#kSdvQi)K_)&TuJEMk_>RwJfP#rOeD7( zY2Uf%n90&ZM?O}q^f5`O2d8{_r^;GjCBJo1v-oN`QC8mVBB9FA@!cJs6{RG>_mxIx=JL{dy{k`c5qv4mO?moX1H6K7HapM(ARA#Y8&T-7iKte%|q)Vl&Rh+&c zq-AICbmsh!$mXdl=$lz?#|WkgozIl%H*;f-Z~4C=S?p!guzo0-Af9_Nu8>vvsRvy+ z-@e9txXMf6T(bH0Y8~lUot!7zg*}=j%aGmpv1C8?h5OGXzvuW!ABDazt78n?kB3&U z)v@{hiiDZAA*{Qyksd5N8z&b#9$H-A$nc>Jik+2{7Y}{Y!qmb_;gPnkK1vNOar5R4 zZEJl!6tb7{8t^vK+SVp09_0UE(~WGb;k4bfFneTS4o3?G|NQ@Kli66gc{y2s-skxt z$MExAecK0Qo7&`oqJ(z|uV1`+;u1@;*W0mGFMjWacUP}JCHFqH`w`uie3H!jHqm*x zCu5mREXhSr$QNl)XUCpjMV+X-)^wWVAhvKRtyOWo#%4=uMA5Z8PI&5?ZR&^J^_gp1 zO~pyXtvE;iSN}{X{(59poPX*le9)t?O_vjo)$(+ykWaNYYV|x)B>K;<{#lKG&c;92 z;eTatus5m|Miu3W(H)uax2rn#m3Sc>_oGJt3c(4Mg|?GNcHU819{nDP9);QM<2;dc zw)sWm@S&Lc5%V@b$0LIYl-S2#+o@uX1PJ$^CHXyo{qvUptmRLKC?dG$Xy>!be!MrF zIj6n&;jPYHt8 ztlthfinyb2e>swW9Wv#=&gayvlC{UbT*v?Qi1AaqCY-M<3){HAhHZXp^0u2kdh7|s zi6foIe?H{DKfteigh!Ik^s^B>F3B6GCRFc#$3fR0gM0pj73zo_Ig*$EIM#+TdHe)d z2`5C3yykvbD{y47-47%3$jHAX`k_6Q9IDR!h=|#jpYO*1xG#{*e_jMXPwdg1|F|5p zdHlyu@GP8-4zjBS-0~wT{ITk{V&K)$M8PKt?Tf#CUz@9XT9|_kt;5x@3hcqs2nJhb zrJPxEkptu;xtMEmn|A9Q(9X{kU-OixflLqnC!RTh@e{5Z^^<5<70 zzhHNHsZ7kZLq&tTGuC=p1~uX5kRt~>Zrd(kg%Y`qY#BrU3K}Or5T_4=Js{^XkG_xQ z3s@K^9Eh|i-?H|ea}QW{l4~QseWVVyq%^b4KBOms-7B$cIB@M*0U)| zw{`deUcA67+5Ct@z{%x9%*;L+6m(8uxXAKdIy?0U)0Kr;lmclGm+0?D^i~X~KgEfF zvv9@&UfAt7J{HDhcipvFv##+aorcE`XVabMww`KY%Uw-TNQ!mc?6V(sOv>OH$WkwE zuXyNIez-elHc*hERZ-5gOFJdvyEs&`=WN=SqhH~-JL*ZjA62$eLmsB(w)2@lSY1(Z z<8W_j;CY5diBdyW>1u-qiKfG+VyhNoDp~vhZ`5~QDNECA_}id$YYexUs*b(1e~yp8;AZc9U+#2E%v_esLVk}F zHH%jH;5`=2()$dB=0m%k3bGmZvoEpXp7TDeH12(`O{0Q;tNU<@r^5S|>@PEYxk;E1 z6($CTJEn#KGcOy-UjKfv;b4g2|5|qfZl<^>|DpcJI2<;QA-jQQH@t`tx^5oh&bn^l ztwC!$<(#;qILG5>J>&TTb~ok*m_5&sPc79D$qL+^EwP!=VT28xw|K99sv}938heWN zt}co2&ID2JRdik`TFab)gy}viu5-V1F0*9Vc}WnnS#_2x(h!~v`YjD;`FG9>pd01O&jmm-NCLoeDWC-`d{kdp3qLb9i9)r-kLwJ9vA3 zL9jX%2MZSRe2>10^nJuIH}z)gN*Cwk$QKw5mlnIo*SoJT4D>9%H|fcgkL9;FZ_mn+ zj^ftj3?3I%xGB$P(DYmG_G%+KDu1)eH#L<(f$!lLl!}RvIE@{%uTd-A-CToa1{Rjh zx5cl-nQ&J>;ZoQ2dlS*^`X|36=h-F5jWYjWH1xr?zM|(yTEg`(>L1Z_Hr{bU;)ro6F6f+*L}=8lLPNH zkY2fwLtPVL7)#G3vE+RXuBS?rgKTF|P*73hlVPVh=3JhVPXQNiwsUelPUZ7@BJrQ^ zqlh|wRYk+vq{x1c)_is?RZc>fB7PNyS<2C|IE9U$a}tgO?dC+;*6=`~g%;*B#GcY; z6m^NxQIXtc3}|`=h7Z`oy~`*00^+q4)bZnUa#q82{j$l|7l-(bk|^zZwG9@i50`N< z3DH^SdOWQd#0S+JPWDvZm&o#vNXW~}(?f_g%id@if)<#HXCV zDKP4|ZERKV9AjoxLYnj~>~bHGCKVB~O6w{B(v0Fq;%PfzlLQ=d=%r$=aRsU2SC#6nO*NZ^*6>aQ+^n=M z6}@pdpz>cF3NCBZZMc+rPb`-FohAasBCE&7#vtxAz7$M2Y?nlb>=td^iNpz%)S%(F z{OXPynd2C?xiAn_`Q^<`eR4;Jm+A{+n9Jx;oIvt~&6y6d$j&S+VTEG-Mq;C#x1v6f z;Nl0`KGI(?x6k3?bXdUqz3oLj10DGGGOcr`_np=v?q6!*FKyH}D2;V~`_7!kAD{U|MexZu_ z1A*P8Yrc&8i{3N9fbnlBvBu%kCFg0eu?}M=TkT03+r+5NsK5HKLOJta{)41Q9Jbl+ z43qvx+oPU5=7YThJKCHlC?`KfkpD+ak@cKevy`_hpM2*oq+h@*T2}S6_CvNk&(Dyb zS9>z}6KqTlo(jY{%6@TP#^`m&C3o3D;jX4>bH8&4#^1 zc5yZ>t9-SAahz)QncUu(58AwZXUci8*sv>AvEQuz_}@^`YdDamBme?hyOk9cxgLHI znJuwjTEx_wmn>Y_XpZ6;nLLCL^sQ=12VjfcQ$Q(V3_dSjoU2HOtW0yjExo1*w_3xk zCubYt{Y0l2e)1tN9%`Ybv59BIC3yQRmCN!cjq+t=bw1b_*;yECI`?SU({|f``*Jax z?F>10)1t=VS{ybWdo58W##l9IsHH>P>E0k5mxx8fz0C#hJ)`z`@AMc*YGeHuZ$7W< zZ)muaB0*ML`Gmsjnh_NrA?h;Vb<~B0Z4$Xe!`ZGh9>bPs{-x56SF-#IoN5*V*!?x4 zD^jc;2U{arv$SmN`VFt>;#}I#Zvr4#-wUJg(qKZP(e(7$T!yiZiS%(!vnh5@J*k|; zBWZksa8{P&s2T?#nqd<9%0+#MEiK>{81I}{X`LAi9Lc`_IgcNW19u^WJ4>ywMTy&D zc(4;LC(VILGq*+Q%5A$P6HVvUdOEspN&G4;Yd9Vek;40<1S+MHMn*GFj-6^ZeKeC0 z)?KqTxgcPeo}3K$wq@)kpilcnb+t7Jk$s)&u*QM+@%3u`DDBL8GBwJ2*NVxwjP)7@ z3e18Pv&wfZ{-DJW`N)Bd~U0h_GCkdJf@yD zOxzU`9(_|ZpTg{j+n!l&5fXX1G5cusqW3vD?2F8h)C0dM9!ad3zjJ8a|G{>yD6DRv z3{GI69$$d?y0QdZ>wPW>Ym`}k9ve|`BTI>|1tyI1w%*IO#nRLB71+bXPf^@vtIDAv zA$=H0K(9b_X7{@J*|`Zgg3`+k?%dgBLoWeG}yk&jDliIDQa7_ZuGx+Ff-%h+luxWFiQ3pV9m0Vc` zG?%QvN)@SLwB=@>AsQ~YQI^w5>l%3A-g|Cq%{&ImhlS3g9wbe}LQumLWwQD}a*=Fu zuWOP1&6}pty{>=2qCx}j>G3nGSxA90R(WqZ5a-{b)02m-f?MlbzVWwGQ&T4jy)$?) zn^D!Uk+Y#{<|{pouSOx}^XPM2SUq>e9@d$#_<8ktgQjq8JcD1tds!7QO>DKdh1p*@_a)YGiZq2Yu$d_nN(V*!Tje?T_yS;8?&Bo}9(Fiadj0KY z--5Vr@IjkIzg$jLHIkQu-6z+uRp?;7gJ=%B+f#A-El1?e+H|cn;iYVfy3+8rcVYus zXA|g86aJkm(uY^L{;|!kAQ8w${R5U0uDoPpr_9AW1?W zXV-6(qXq!YFXVy#rh)21V@e?R`kqN-i&7WPmpvQWH~E;S;mu9(_@{aZqddmW{C&@fSc za&n!fJ^GwA3aWwv>9Vg+PL+P^;whOYH01)cfPLdstazjyKF-;+EWRyaW0Pt3!y>#q?DgG_<>U~(3 zz8L51z0J-Pg<1@)ALk4_U4Y4={D$#cNOAq8?e9TRFHsr!4nFKeY#r3arXv*zDhPh1jUZH}=4tj0 zc3}49(r-AA9v!qQQ7h&*8Ovu)Q_5iHdWuW1sa!KD(w(6e=5XXRIX9CuKV?|b_51ut z8c57{-P@E-r{;b1I?N3JmJ$MnEcpl{atF?&I?8tTXkmtYVs-*j3!7z$F3n3Cw8k#b zs-IdzzHJz%QM(?{A!oJlZ{4J_4BPf-95PF*oTG<&zc3_GF+;6z7_h=Zj3j_!hc>3{ z3Im`>Vwax0mP6qJ%RtgjAwK9B1*P{J4gEt^FCXU;J=ocoX8b2c)shl*r-!iQ4r#50vll}| z^$y^9q7_83z!+J-Ac}XwxR*NMt3$1$IIBNQ<~`I}J1lr}m3cFtF2+V)#~Gp+OU1sG z0`Ja5@PUcsojZCDpfIWR8REFb&N|$}7k~ly6^kbCsK8*5>quiaLO?G`{P5eCH-RzM zsB>OQ>Gv=Cz~wakeFuaPR;E!YL)Ed(8C_`F*X}dCBtAP?o+2tLy83NEyoHZ27lU;% zUMkzd|KlW*k-aG`x2?Rr1aKw zc44@XmYk0X019vxvQVyDq{{Pt?ZjC z{{bH%+9~Q(z58!_^SS=&k5<0iB&g@M8b1}WvB&XSjw_U{<7B}MxR=7}>NWUJ6VXbU zl-;KYAbojPUVcop^}>o>i+gWXowg^XLE>+krn_r}6$i~eEliiPYkRu0w6tyn2$Ei2 zRQ+v-3767Ft~FLr`i*RykhjJxZ4;?J-Wnu$AvgnxtiYI*BnUpOjw?G`JRveMQt~|F zv3S%=IC`j=8h25AU@pqrPhYs9ilpKYO!#+2a#dxLZVY^Ko|-v=39NzxD*wVA++a` zDb9Jf)NVl)+t1mjyrvoFwrkXG&spK*w!cyYfiaIBb%>QGf#7SeH57&e#c z0>NlW=VRXc{tX6uc=P#b?*XA1zJ!pwGvp5rb@(Ps)#5ON=_J4JXqBIM|1=eXg+w|G%3SkB3da|H0 zP_gaP4~u~cYRcjPwlN6~kxtc#9p?ee#|kL3;s7xYI@3~~w+tZ=+J0>`4V>;+jkBm| zHIyH^43kFeoB5jx>ekI%P)SkqS;b>_dL%=c92bkH=eef{dY;0+f-o%8LDL}$e6;XP zd~hg>2H8kRb{NgDYH>SVSIZ=(s$?+4%xw3F4tF@K_6@*qKzdwg$Cd>lnDUenK24@> z+S^OzBWSwlM>l9fecmJ0d5I^mcTVMo#?JLDV{5<)ZDMF4&ICySiEKZn9LGDnP*3Bn z)_($3Z>SwN$Go!ulu5rLAlY0}UG%8xZ}ngBcCv!amM{AYT+-(wm-|rX6KkNmw*zGS zvi&=3v8o+;t39)?Yh_VIGsGg3FR$G(ii7A^?-9)g_|NaUa6KKfn*hcdauKYsryTF)MoIaq|NnC64 z(v3S3Uq(EY?DJ`97T*5)v@SE#1L(*Nzhod9%l20rHP$C}Bm;nd&TVS9 zqw=ZUw%-UIsqv#M(W?)Nr`G%QTR55mu|((sT}8b?y%3NohS9YRa1C+e@QU!UR=5lOj@IHg#lcgG)xDnlEMJ z`f1s;iQ4VO+xy`O{b2jQi>ZigvMMczt8*C6bA}a@H-MdP(ABz8)%TQ6&S`7o*O z01E2MVt(scWx)N6ZDIlYIn}ewZ}5D5{S-gP2kPBrm#ynL(=Y0Vh885Dgd-4GevIYa z2lB1Vcmg=jlac0mg}$K*cjBWtadq$jnv}U_l!+r?)biv)JdgOvzke4qD8~=yJ}JHm z3ybP&@H%@r7S5U!^%mi;Srv!7l^&;xd0Frgj-fPQN`#4sXrCb7uY}rb$HoeCakSOF zS1`WSJt8`;QSF=Z zy6jg6biKVWA>+(}$UZtxwq%WG59F40~s$YP-;qhgE4d68FM54B+lK6xA_8$Iuaerr==*N1Ur1`NkGjq2_=bRy%mbX zplP`x4ErJKUQgwA)(G2~(7mc4ocbu$QwB%gp8~%CeRB-|7SKsld{z?xzf*^Z#eOHZ zG+&2=ghV*H+c6U2f4{~z0Kx(NWuQ9z=B6j4_yZ6fmVn47aUJwd-+0S2TDk?ms$@w> zft#ayrXvX?q<)`a?prL(-g}y*->eIFQ{xlY*>PEKH-VTlgT& zhgj)AX)#j@BuClyn9t@@aV<*gCbmQuh{m^F_yRzLYv|GbpwTY3x=&(-a#XnNe(Ffh zYf9`d4f}3|8WR}f(jAVPZaSf!!zv=#beXVBtqP$PpJnXED$tyg3D`DMQ1i0MX$}|= zYA!*QcH-9_-YMA}b^f$R3FLh4Nkfj2Kq*iU5I`kyXYebae(5gJg5mvq0jTUL)N~Gm zTCw&>V$$DAoVwgtVKXZBBNqpVbJl+;veaE07?etj;xx)J?PD)79xSqigcLGe7z@hb z88Xg?oyl!xg+odzDnOkxcA=lk2#4Ez@L~5Zbq%E^};zjPe$2)26S*>^vOQ?0<% zh?o{#3>BOH9#8~Pu94hPOLd2L4G%+2AjS_R^_3g8#v1L?y#GVD^_nQG0YwbBP1m)w z!B@@bLGgLcM&JPvWpj0e0-I*g9I4pM5<=lsX6s0^tNb!0P^-bDJ3a8Am;8NLXlP`G zqf|5SBndUI;5gdttwKbZFBmYlw4k(?e@J5&xCF7*!bIlU42=Q@=5T-3*4KKKpV%ba zZaRexv+mSZE7U+bBvFD?N8|p&p-=iyK!tn;9QYRNma($=jPj3&C+7;uz4+T(p9yrP z_2xu79}W*Q%phf8tMgclo+jP$^d8H*d#R=ConB!{4fNE(H|#!%E&$zzqku~ z3SElwVedYNb`GTQ>g$!-0TKaG5Bd~k1vl=|*!ks=E?IW4scgG6JjC5pI?h&0q0244 zhB`?S@H-bKzfAKus^W=MXHb+|_-_eA$%Me(e^*XF(lau04CT1&SgGj}@2$^V_5kqk zrMu9$>rM`F;J0-#b0y-Q1POjVMf`ZkR`TCKpVRq_U{L!>+6j?ZmsJUi=_UzVD->{S z(J4DX`UJn_P!Ic^tCg*Nc9Lk`P9C)wJYfaWY68buaNU zu!ma}@=FyhEs{lYE#_b1C5TcaoFoD-{~#bNKNXk_nA&_8_v6otA~OF2=<;q3tA{RJ zUF*Qe*B-^CkgISzh*wjE0!nibX9^*-d`UT`Zq+w`DSbF5%Fb#@kV>?fVzzo4Zmb*1 zc&y6XiaN-Tl7F{QHU!68cgm(~o)ouhu{TY>KPG8>y+hW2&U3)LgxQj#-n}V`N0!)m zYjI)cco;K{=BdkDgTdCKdQpgzffve>16T6~h|m`CaB{tm1L;{*p>1iwaJi>q4Z^4x z-sbaX=dStjO@(`*aaZ?7u*2u)U5}_1nrnd0BR((mk~>(pA#ntu%_i7g_H2$TP+hZm zm~&|N%ipAjN19GE2}R~9%2}}_jqclMZnm{|KrZhVrW=G^0j>#zC4@ew+4LU*!2`Xb zm=x=jIvo{5yW5rJHaQ}sh(7_GQ22RUaBnoY4iyt$3F#-bb_C@wL9attGS% zY?c=Z&?6KRVb!;S63Cjy5aF#)5%}XXCsyl@IQBom4%a~v1Ee?#ntEC9f~#Ew&d$)1 zn;{;#YtvX$1joVBRZ{P%<|x^iYh9Sku#{4Go`q8cg6nd9NzLxzaS%sy$(!PYwPu0l zR=symZ)c@8OtV1ir(`;CG-htKq?h$7U?G zC-{_I_Z-T(rV+WW`rF0em|&S}^p;(2dkfP$28Nc9p?hA;s-M!eneFucjJn`)RK+@v zU$*w6JI+CzMvGrKzy0D}G0MrM2oPQQn5za9@%0*B(dRS+abn2Bot2@Gi>?b}@SYu=o9FB$r9* z&V}<--?8h@x<6rrx#LuX;l2-M`!n^Wa>E86s8Ol~*~=p}BCp`;a6bI26SX9)5 zFZOCN#3-i5cgL*zBfoNPgem|zfCtAwD`X;%8XbH02l`Ze=5C?UxoE!RLO+Dq7?3=8ae+~4w37W0)vHWk_;t> z6_N$P1JOH5BOA?jx4N4eG>62&Obvd=S|64VS63*dT>-=pT>JJK_}31fp;wA5gB*8n zn9q+_n_I)bv?B9uE4DUtO!Sp@zvBw7hxq)U#eh4-t*NgT_^(V^4P8fI*U#pyQ&%}I z{|4d`sK}J|iJq3#7nCVL*E~hcl)S(_2vr-LJfQXpV`470{?0SVb|3)*_?FyOp%QSf zH5(X&YXK2}?AmyyU^Y_f&HAr{;DtCvK+6cNUKy{o7%3MtkCF(!GW6*48SjkU#gZi` zmn{x8hYHNpQV;wo`3rzmt=MU{7*pjp?o5Uaasgd7MROY<>H4>}&#{R*5g&ElMq{bO zYD}`q3P5b5AF=6>h6BuX7VXMI44$~Zns)wH6#aCu|F`;`yeg!{h7d*!;6Cu;L=LS% zE>#i@2@UO@k3Hr4y9bm{8zjY#~sLNt(9O?zkpPXi$&+~6sq8%mxy##K3Qw=vtrx2U(!pN~|R z-C*irMx$G^&v>~1U7cZ8&0`f@0|tH#YyzrUwTs=ZvxtCwA1tjpf6eAw zfEzXlXGhjI!lcgr;$Aen{tG6^6om$s0L;PBk=3LF06pT6*F->;f1ameuvkK6vXnt3s8^YNpt z?gGFe7E>JOYJXlS^0#{u4aYOWdN&(7gU`>;0H_f*d&Z`p+ln~cbUnhZVV9SHbcf1)&B8Q_WQ!PN z;AefZgJRoIeM+UZmv)<5XqEs28gKUK%-_)r5EHXY#2iFyK2Y!TOhT#AEfv{BQ3Zir zX!|P;FzZiLDERHt=@H`V6$x6CVvE?Dk5HmC{2=RocIEjdp>fSi3J8q5Ek7XwUtAta zwHx#7+}{_& zX>)#NDHMWEL^aqfzjT|9ln=o|T#=5Ps6OmtXc{|4qE6^N?4sM5eAnBWwBG%dXhd1r zMz`9kMz||10k^ru;Sezii5OUJC)t1?o&j@-sWGCLjR+ZmOHb?Uy!^1Iu5|mNfGfZ+ zj)V755i4*%ZG5%2F=yBS4wD#q%+6$3;QhBbKyrY0BL1c)zCov$%N7nFsK(M|WnHo* zb_?;&w76EwpKv8zA#O~bW^v2{+TzXufT^;Fk@u`nHQcV_CQ-yJDlCX0YmrI>;&{)yF#BR%X%p)&JOZXQrT^=de-E`(vEZESW!gKc9Pk z^*Wq-E~szgwq1~Gnqa{J5HM`m4_bP5HoCgc zZ^9igXftKv3xLwBUlEM6dHTif{;$fO?LVDI;!;7)=|>%v;`!DnU=!XC^vd4CkH7Xe z?bLm|;;7ffq`)W@{|xXI3ao#*sd*#yQ&T~EsVK;#p@W27m`~-HLT0rBUz!qP14vMb zQ_qNGmX)tGyVu3nx4HyCfN63`<~(B;+7h0A5vml~Opk0Igk*pXj~@!Tf;(0r>K}jk z(#fq`Ttu8H{w0;7bt zC(im)h=bev-z*ou7{VeRn#1jXsiI!tR)#!#T?muq7ET0QHc-5Sar*L%g2R|R*llO; zDPXfO2aG{u0N@j$5;=^lqNs~?UYyxk>|vmCUBBz^{5J75+a(iUyXhI&3>7#_^J7Jp zykE>Y;Ku&vuP_ZB3D%(;z4~)1rV!=S(bZs4X#33#XeG%VcU-Dv`N1!r z?*!v`SGir@mPI_mp4djPD}pm&k;NJX7JW?Fx63wWF9(Yre@2Cr;#WsPeBT9NKZUs; zL{dUkHL%m4eXu#unpTs~DvaIF?TiC*TC<;`4kC*g9?*%wPDE0r-|960pc8SH#;g%& z&Qf^Y6M{n^A9{5iB=o2pqj=Xh(dR;E-B5PQiPRHKp+#yU&J!X*7yp)%0|mZ~0&?Lb zx~dQ^SG-CD~Y=m-3NlD4T{{`@sxAB6KLY&i_+Q{R@KgHp! z*p*w=s(hzMe|CsJz6KEmTw7Z}3GXgFX8^k;o6Gic5r-h++S|OF_<*sw^Rp>^2V(_7 zfOIBVe9Z6BECGHn0$sPy*+Gm=g?oIZd>^E%vXngkL*H8#TmkDEU?NI;=XWg?ylU_P ztt?TaybEneBTPpR!8Xlt0p6Q& z141=dh?VX%kqqxAmuS0%{s;mV`v=6}09ybTG{8Vm{9SWD!JWB+M7P?MDJV=nOEJXxF?3k!e&2H?Ck3jsBl2S$vlGg6Zu^^8-G zehQoZbU*ipz56j|ojc0pM|Y6c`*3`|&0gIKKk$U~QQ8k`8$)TYuT-{Nd8%;ODa~ok zm;pEE(ddobLb!kTFrn4gl5%_i&L!{ z7-?{ht;>UA3I{O33SisRGyszk$LSbIA2dTDrV6U6yWoa41>=R5h3p5`mx0ZuWsYGU zr%23)OI5l-TiyrTazRgpLmP#cQB5?THHg&%MfRLoyKpbeRP{}oLKBY~2y3~lh>p>1 zVD=JSI;43LW=M6bUtBQAwVmru7)cLEKGPWaqci1~zdmfU%Y&6$o)1hMnV%$P=AEep23#w!rC9i@LiT~`#>m+3+HA7;4SYm53{vEsfB!ki?p;bc*wUga zA+$WgnkY<)oaWQLwFwO&;o|F3=M>!F4Hmc&CS(!>mMAOi;em89@Pmm=NhvPagRMlD zb_qJsw|s;Oi0@gwvi`f(l@*y(5ntruK8#-#P`z0x0zaz@b( zW8R4D3);{h&1PEVjwKDhE1475K$HZ&ENB(nnoA2Vp&moGgD%)*=jCw*apPV(dFJL~ z+bAX@#hWHNksWDzX&Tsx_k+A};dfYA<-Y@LeB>^;@*27!blomcC(ngUUE~i9ThHzt zC?y*^uXi#0FmC_ldWF$R2s@8avX(wG(M|`8QbruVeP$R4eT7#G50`=Nsu%60sEa#X zr%T~Eh6eNnd`-b&q)BGrP~xtE^X7bC^4)h;tvO)oM~?~wfZSDM`$}T~{4@6W7b?hp zd*JjRuTrc4k*?4xgmA{mR$;7wIS0CekFetiG)W+ONP>{`cY9TV<|4H`BoeoB5UIS) zWPs77iSD@zL61e_1I-Y4Gx-=~>h~U{OZ@1;5h0rp3E=t>RL~=(r-554|hKb8}s35WV+A+owdp3~Ike48SmP9}+Rmko-BW6e^5D z@2Vh~$*Uhdm4699jXbjaxbj(=f@mj6#WiHbHJ|elvgy?k(nC=av5Q!Et?u4!L)a_L z{@^RPh~YO^1qhPe%>_n}d#+a9Du#Rx(O&)3n0)cyn-zW)e@by8C-FxE=;VN+vc_Zu z!R@hrI6ka1sX#srrsqfX?Lwm2Avq{{q4sLJ7m_VL<+VIS42-eYR8$N}2@`lukI>uP zh)eeXYB0!@(s&@0E<(Kn_fr^7k+YW4_z3pU-k(Yk0veyg@&iW^Up6RjM-CS4Q-tP0 ziD{Np&3kAGzG9lGN9jn_JA-TE{!@qPUsmH^I{){k)W3XT7H%~C)Q|XEQG%iQG`qR^Sq&Xjc7TaS9E~fK31W-Z(g#Z8jGcMo~ zN(ou``P_1C{^Eh=acVBw{WNLE08s2yk*gf!{lU6>y}Q%E44b zAy_h0h|#x3@1C|tZY4z$M3?4d8T<+05|GAgX>BMLH`Ac0a0U#c9ZQ2?%WMjT!Y4nZ z3pziLR#Exk$$>ZTQ;vU+6fzyL1aAzstx<>;4^IFtPZ$lr3WgtOU+ptMJgnX6&|V4T zNmf&hK`uCUqw*8m7pIfr+?+tr9f9Eix!D;&P!i@&LQB~svmSwxzJ7vfsZR9^QVs(b z;Nakig30=4J+;tD!>O4S(Am)9g$c5%wwlm1E2`Nbsu#A&hU*F{V`h7rH zBn$}S`izV~fF8vWEVCrp^-PaI=4xu}wiq^_73cWr<%(HoLQ3d#h7R&h=(b)I0nmP3al-^wa~yTj(nQPnKoo8 zpxwY1s_4j75Gth|K|DM=0v<=O7eF6At8UF{dIIRp)QSTZ54uVcA0fTYR!FDdz@8hT zG*;j`Gy7Ipf%X-;iWsPf5#wI(CK`rAyaI!vm;w~XNhYPWuW7Zi&mcQE2I)YK1ByQA z<<3cK(g6s532dBRuoUg>?I4HtfK{Q&)W{92?82FBVA5i>K#cETlSC{OmP;nYP=U(Q zBXbV4Ft8(rLmVd}U21ueH~0GEE5VF6U1djLQU|RXnKwUzB`&ZqjlxT~@nVbMmU@XN zuosTN`61mEWzQ(QI=4qeiIH&`gC!@9-fg`2{Ym8^seE4_r0u1oAx#s1A|XtZ-2>P* zB}K)EYQ#qgW$bT^O6l({Y$ijLBgyu@hC`EG7cjbPQI0SY0CW|}QH0>?3C5wP+3~eN z9`ft=Gh8Q#YXwc9JN~%Eb16eNffa`3{62$XcYx6T7L;Ph16o}UgfHEST?ML~2`c(8 zlN{y9<~@!>j>_eC(5Jyo5W{H{)a=frR?u`F#74yP8F>Tb?50*|p}Z9|DRPb=9(K4T zlB>~Yn0fDEd>{#MD5vD>%U504Ws)#5@DS37BXxZEr;j zR>9cL3yd(>+aK^zBc6Sv{bqg?xW0f&;2`54;K!~A!F^-fm~t(#owKVtD^?1u4SaWK zyR3oMM{4gY_nR^oOV?x^Gt35%84O_0gnCcic_IJsIJ7nlRBVHPvg=OPbz}|@vbg_) z^Y|M}U|O&(wG;w})u2Ng@eqz8(~#ijJA7f4utp(sT}o_Ec$OaHL0X0Drg z=B~}hqqq-w&b$enCPX06kx)1x+VYy3vFles(QP*;yK%YoB0lmPCfLav1~8q$(o+s% zRX(`~Ynzuf@|$HWgvX0|pcge$UGMhJUp+nE?$#3YX`PE_<5}a0mnFoKkmFXIIfUa{wM#*GB(?OTHEU0M#W?P zz1xpzXiU$Zh`N6MI`MVAQ&&%@%Y6#3yL5s?PUY9Lqc2c+hexg}soXl&7e@W$hDZSA zEpG4mTd0dC)$S98ng%xw2J^LcDn!Jd4!$@<7veM`JjG`_Yh$ZuYb%WrmR06Dazsuc zW$sNRV{53q4Lc!hOynI6f-ZH(f>&>Y-C-d+@69?TPc`HwoR2vTEBiW8zUL;Fax8Pg zH$4>mnk(c3Rci67DZMBi4#ceFl+F#g<`6?k`fH>o;0Q@4WO^EB3aH&_s~3U4HfFFD zyk|YxC;vj`_%HuAKN_zvVMjR$+%h0me+Ar-Tm0FRU}>=6nHbXM)qIGwv{9BcE+}nJ%xML>Gj0B~6qRO1 z`iG}!9Ke`ya~e2u67c1g*#U>FgA8n-;>m!UqmU@&9Ro)E6F54Ut;M0~riftXO$c!d zpg=!-RsoEmOLv?;3Z`$!P!JMt!;B`yEHxpV9mu*A&nd0yF0K@hsd`jDZz*~P3e=T# zXz1rqi-S-q%tFT`aM}Twz#G#9Zp%;O_9y7HS3wxU4+b;bi3PAy>&cQ`so2cV@~D9i zq$Cb8vjr!8&e0W8u)?;p7B_PbR2|h;L*#$iZL7}UpZ2_nIpdx_Dx2fpx^%ILHooBc zmoG@y8-lS|g$6!;xv%YU0XmDg0Rw$m1ns7qdLJf3A!fnjr+*8ersfFfkl|;}t5}O! zf=MWDjm(9o7iN!KjB}^3tUCK<=$)9qGaw8|q$d`*dep&RA5l1Dr}hwO0z!zr!D8#1 z&LHc;>gl-!@X7&rfo3Z&OyP8<- z*(T&f?Cx9^(p_?90i0MD*FC3Sm|Tcm0oN?S0$r@brSy8IxeSv2GiT2DY#vLc{OJTg zQd2cz#F-hXz@(j?=!iSCaeL>sk)~CBd;f#@ddbK^W>Dib8R3KV-dGMpnQ(!raNS5N zQt^bzv@3TVK0uRFzUs@_(|VweTPoep4lkU@^5`?oZ5}fg13!yn_=Q+O0~GlB4d?wy z>(ngDLNbi`NyWRt%~7}CU2UR`bbT~h$PuHGKALhOfy08BL z7q|!zJSw~$a1);tyhAX~CT3*0VSfu}1{$Vd!c~+id%#Rbl5%8)PPVZRx4o+E@t|hB z4d?p?9s8tp?2Swv`6fN45sVpm^5GYbSDmK0azUDzRNRfgh6X2s%S0(W8isTzu;A=~ zk%qj-1w20>o!H@S?daV2>1q##Dy6aqIEdB*iyoQkMl!YhnSh|$ZSW&d$JJM1%c+2M zorIH%fs>?cMT%VGTwJ@kZZlAGO^xeC;6N!EmFMZ%w18I9W;{g9jWYusKMrr()=n{! zas$SmV_)J;HEnwVaAGWt?kC%9}27#p6!XaTN zOkr%2bq5`M4|eeW2Scx{#g6qQsG*fGafn=RZp@{oBbUxq=p&CU3Y!$9gG z#M>lj(g3%Hsc|t2T;C>%@UvG(VFwQbWo4P_E$POP=8(r=e>>?wnjBWi(A6 zpe~D29eZ_kFEDbGBLHR;JrD6GP;s0L34_z(0_XI_7KgXabR5i2c>etPe3ApB*^r99 z<&{6z7cx+oLq?{D%IZ&#I@#Aw8+%%>K43};z|;G9Wi@H`09vnqdxh}D&7Y3V|F&uI z|HF*@-}=!h_N+{KofeV(cgpOK9(la_9evDFo<7CA5tUdVzoY?}qZGj$VNST8Z%7^_ zret&?2=Z!H=LVtZ*oSpC*^MBi~Z9pl9c~(pts&e8ft-vLV zI0DkWN<(@gCUiF%qRT7gStqX>LGE9S{@Z>X58YNyFg{7DjQG6#tTl{Om(xs{yNEZQ z84W_SbBt}b_rglEd={lg;Gd6Bc^|51N^ut}TmE8LvAiHyF>zv>^Fx3RQj}j-CQt7G z4}wD53f>CLb3CyD0}VHv?$X!_Rl{HF!M!_Q55laR>xp906Q>dm4f)`zU4=jX#QSXf z*(@d$NubO}c2p4v{A{8Fs^zv%>y=kZ_AHxl;Mn+B462ycq+aRl=4y!We2wfE8 zpT?&je0!E>2!!41CgdFu5A5+XWUri5!y6}8qTC-AmClZC?Vsi9!ky-DS=++wRc}UwRu9M^=+qY|L zTcM;%@8W0`2wvI;WVDu@Ms|F^0tO}#+if88d;K+5p&%JApM`GIf{{ummU-*8lm9wA zqOBt3%O2=XtRph}%)@Dv`15H!@I0T=MZ9asbQam?^<7G8X4-K+G66`jikwWIQ?*&7Aei!Y#9jjRJPue1x^0#|%w_f>y*-=Am@94+(=xO< z6a$OM0~l<%Q#GeXVWcR`t`Y6*JiE=|g_&Z`y^xaf5%kP51 zb_*uyOn7R5D;XIHjdb7?P0Z740(|ZTvy)wTG!zNZ(ZEmR^Uo6&%z?4KC956$Kf*v! zGZzk8Re7BSDp8wz4lw!2MuI3uuv<>WZB?E^pGHgbs()UM!uw7VAh-FUcaz8yIkac- znx;{axPoz5NG zxU8*rbvW1OPNgmk&efQbfk4?)sA!w&D-U4|OK4nCe+8}J4e zQ0P5C-<7_osa6q~)K+|FagS=p?4%|P{o>vl1_R*uaVS)nIm^LnTYLDPXZ2ub1L=6z zoyYvTnKV5~FCw7ZKy)bG*g zf*?)`7*50Vt-*Linzagb1JR9EAW<2bM@GDGGJ(5h-D!cc1UCB33Up)&ZDRHYM*OlQ z6EaT68^N?TsI&?3)=Z_Krcc%CfMVdyNB@N)b}Tf;A_eI~ru zZ`8{J1b#D8hq*tifd*l+y*QYh!n#v;*K5t=adU^qf5AIFFo^fAt9+vWJNGmNZ z$@sIQCr7w^p8XL`<=Qx4eDCvp7dMqo!q3m{EYAH3o}DemW-a{sXZ38lHPLX{-mpOf z9>R5P5b;>@3Mxy_p$f>9q)VWWAEd6 z{_s4{TDrUL>$<+5;XKdJ`N5G|HWI{?-JA4T!_0^dlhS5uvdq@6_%mgMM;dbvwK46! z&;iTA_Rg(A<|i{3$|VP4AV*G}-hW!s*ZETCZiWy-b7b{Amz_KBxDj}`oa04Xnh^j# zM$|c`K5Z#!ql!w@qQ_mKtYDBebDr*Q&o?!cLO)|8p`Ih#uNoj)&eNw_)1yH zpuy?PU?V^6wDa>N&tLLT+d(6B;7M)lu|Ua;yL7)}p2>1bjom++;ayl80tD=gk&nu&$&>XG z(DPVi$?8NulKFvm`@s+(k@Tuy;?40=WFhu&j&;twYX_r5r|0bGxi)G$h!_owuYO99 z7;f4cHq+db^nrAzHjK>o{(Pq@9tApoxp^{o&TfLo)Vb%VlZ@s$mYka}Wbb_q~S&c^Y=? z<=ap|X&2uXs1X;_fEaw>8mOJp&xRwNg%NZ01|D57s0Qq!@J%Fa_7t37nh*}Xek3EUI={Q zd>Y~FVUru#?h(|f`?DzDh(!3IyOtuvCIL68<0@C3i#5Dj9Ve2*S^x`1`$=4Aegm?N z12delKY11X6A*=UVF9d^KI6Ou5^I_Edz(pVpxR-KF(r5u;HbOEeD+c?H8-DyJlhU? z1=8+6ibGU|v&)aV?0MT|;ue3P7Nkl&okM^75YN|2O_Ses1nF7+{SRVm^A27@t^0pn zjq2&asIm`6eB?s^|TQJdz$UzGuXPmW`c#RE9u<(aSh5zF*Wpmx92V4RfXqx``4t z-I#3IxwrD<(H%ZcaZ4=@w-TcJ+`{(f!6)bH6E5KI^c%?ycXN`F|M3_^vW5()}*PYNlFDppGEEJGOe7zt86L!q%I zp~$%8W;po2yk%mdqK3tNu<8=~f|uG=rr}ZYA6$gL7HR=zQ*UPe-|xfHQrNQ%SsF_v z++r<2rD8BcRx*gz)kUmzmw6s?S>svy52XH|uDqcv_G$I{Zg?!;p{SqD<(gl$^?)%; z0*1xN#}02K-lM2_Ixu+SMrKsUt24pM`ZQmWAhqDs{<}t>y5ymU_z6)vY?uH}2g&E4 zd~2IuJ%Z7~PquVUyh?#8e9RhqTb4?p{%9}wA|7X4$e4>yBB;)JcE!=mD z#-;Fh-QCcNdH}PUGA)o<BXxye`T%|^CtBBhziU9vR7NbyVQe>wAC`~6DH-hG-eWd$eJV~0rTJA2E|N8Cvt<~Lg zlty7BlAZH_xXd&tG$QbYtB}P!hnU*t)~7t8swkpVZAf7YZ;u7cz_?S3H5htF`O?|^ zvl<;SM_3;XAE`lnS6 zqqPp@s73c1X9$}cEt)*YFh>+uwXBwt_LYa2T_#ZQ^QG(NxFfV?D-_$x_%wgd`KY!- z`f2HIfhE81Esp?oI{fb9-n8ErTP8bFu-VFc^yU7+X*6{lyiMhl_U~1#7}xh{hGi`{ zNQG}B0oxSsl*L~kGPAM<7*^=Z^!<4wh@9^&UfMp%A86P=E+P%*Gag0MU827@EG>{v zuf%s~mKpCI4Nxe~l)7o;dnT%sI;N_D-VlvgY{>$(APkY@djn8@Ro~p@Ipy{iR(vJ) zunTAg>48r7Qz6UKPA92uye+RfM}kR9Jzu^sEgR8;H47?1{OMD_p(l+T5l@!I0wxaQ zD?MIQyUV_B9J69Qyi@<Jzjx&msKrBWMNJ_cdu)R9`8pP-#K5aQz|r%Wa>~f z)ppwpcK;QBL!4_GP$~qkYeC6ZkLJP=wO-n;d0>*n_#EmfPgS*|lp&Ix&PEH^@J9`r=Jh9k&u2^3+AHTrpeRsoU_2^}H%7h%g z(nSa(G831MhzPxi&leF(zcr=~AcYg!edXR)Ast`IRM&#Z3Ns>hvUOmH_Q=KCm4!Nk zE)dX6(>V_rzyTViA$zR!gLhy3@de{Jsnfq?3UIp6km-Ocm?zgROqI^wz&e}jm~^*N zMXX0X^~jz6+8(R{l;;|nQWe_z`>EbXJG@&K6U*cdE7&}1F8gv+Fn!B|6+AY<^oOoE zOriN0rACER)$dHiTD5Ar8`wzxV%cfiU-K|t58{Q~11KPL@eOsCyW;{3bM#;mR})DDI``-8Bu()GPOJmqFZCg^^~|ENBLI zk{Rm=8CagYIm)XX8Z7&O`LQ#RIIO&eV%?w|H5$`3;>TaV3ti4mI~3`kj+;Sw z=sd&(7lzI?B>d27m=tVRxbxPrRz=NX)N^?Vv{i;vWdE6JIfENRGAXjqaEohBVE}43 zB05S-L6fi)`$&xQ@(mPzPkaIJNiW+)t|Vk68H4U#q#eVsEQ7&FQ&Y`ssb@t41bP)@ zLC68A7#qj;n2_U?B;vd%Et)kt;dljH=1D7Es-!vl8}D8xNG$>9*%2x1Z#b`Kjgi$M z=`D{-NGWfA_XA%2Hnci^JDx(M0wR5dJCd%5<2!EDNsN3u>T(R@YYs5Vtlf%2BzLyB z?p2(n=}MIxkz@kY+}49*g(Uvwfesj$o0-1+=CP;!p1Jxn3EvgtjwaGTI;NLmWmBvV zJd|Uwh0KC;XG76PX+7kTviPrXiAV^)+j))nBNQRff=@Klz>Xnl+&@W_d z^69Q=N2gjk84M>rrBVQ59w6Nv+n!WCa)u@&9mF&L4zHsI1_m!CuR*HW-{*_=8RO!{ z-Y}T9zFI)srfPz>eC)9puj0Zu^7MEE`tDJ>!M5xL9OeTCVCwb00W;9ZbocQE@_{t( zGJ(L!F(dzgrLtRiz1rDx$wUU7QhkihyI3GuQEU?8Np~B(>11!&olrDOvJ3TRk-?_P z0*vc2Q7>EQw>*gX)`s_`sd;0qK1~%ogm#+4^1{-%vt9Xjt@wuZFs{7$Hq@!9b6zkc zGJH0DZ7nYO5)bok#o#@|I9+{*Ikauig98 zV?)QF5Lgj(<~qx3Z)XGy*4jB@PyH;H^)N>=V%VK*sHe20ZZX^Zj-qI3E~79?7=h2$ z7*3v~$X@z+v?~edChy+;7>f7U0weO66~6{`MyF-G#+i#WRrCCNE`E7GJ4tERK9Fqr z%KU9#l->wl(lVNlU9YWCZs(W&9Z&nEh!Hl}|zV$LA`r0otxsdme; zV6-&^Zh;OZ?pvFow^F-lOiGo4MVzwwC^2s$f*1OS?L0>tN>9_t|Gv-nSPx@#Ha8G% zDN!AaD>_~`nnwSaB>L?^@;1B^XWx02GT3*PMg+llBFqdp#`O2oM5OHFTeGS4+?Jwm zs>IlCw_>Xo(^fwX)0gJEA@T7ky?^u_93@|g?>xsnP3M$!W_atCSji@d2|l_q3d%sQ z7A+pxz4O6J5C@G{=e2ELsma`!J(VZKr&1@X6ud|H(q5PVD2*-%mXQ4#h1%(-_WZuj zF2$7n5?rcM3)K7@R*NOqwq7tXxhI3C?KIeTm}ZUTy+HT#yIJwZDWdg0_9-mFb?B;; zoBB+?=7UeX8n(46qerL8u4FMuBF}Yv&pn1;Co4YI`8_?*_7i<4yddH`9rsVl%lTu*~^%gNMoT zi9KdjyPUGOG8woFbQM@0%?L1^?W+f#V+_uf-d*T=-_csL`uRk)^OG9>Q}xJf&|vE% zh8T%pdOOb1R)29a5zmp1GZr;#BKb*UH}`juRS4FkDNRe>_ELqWs%FGC9QB#azJc`m zUphrX{qSkgSOXs7RO6YaSeU<_esTQH-7|h#)$XIv?3Of<{sq?pXS-wq=T1oR`7m&ZekOXtRw}X zQL~hmo&9HWo*Zcd#j}RpQO3P}IW4sgCt;=88$hO7Fl@Al)03LvE1N@?ofV$0H;sCx z9wIufhhg}lgG7#WE(DGtweiQqCJAVd(OdN0yHJ{-740Av5viSks>zLjaGt~s;u+X& z6N-h7iM6!wjFK6<-SQ@UT+96L3Cj5o;pzV(R~!Dwm>U8<;BlF#RNCVQ1iMMXPDmqL z4JNK-ZKy;`z&Qd;YZTR9Amn;M2E?5b;bH-KD+ra~CXI%Nw9%p{LnLL-Yy3VzM-^#C z2xtdQwVvBv;Niq^cY|GlTGohrg)pvVyB4x+=rcZYV^(>RdQpi}E+bxfDNjQA0qyrbZi03dq zjkpfEWQv_MT;aq@7~=Ow&l6E0Ys(-SLqJFI-?+ptXk9)1Kpyx-5=xDy2dOp`#rhLS^$ab__5^e zr=rXOj79W-uDk#(9!cJNCh;Wupi}L&L$#3G3^Hze3c%2cn%Nc~ASi;07jO)$3VoIu za?5jA9rUlwc3MD`kyXTK0_xw1`!ZIP-WA@sXeYdUL4n@Bm<$pbbLe1iEAS0A;wGBU z`FrlH1<@)w{ku~Qxf^_e$hy!;Hlhkt3=$i{a1mqlS~UZJGvAvp=+ggwb#}0_7T|1W zqQ*Mst@n;lc9%cpH!ctyCVJldF6hkt=biF5Tmc^ySBn9Md|iY!IOf)%%rz(nq@DYv z;wqsRHZ$$=BvT`?p~7*dB^3R_urT&)+BIyjXsa7dMyReu0ybB-rCGCHr7&+p08ruE z^DOoPKtQ#z_-yxC$W$Bj&H&;@Tb5P9iF6<)aE@DvZq+VNhjMt*?k@-TTWe}qLSbWL z!|8S+szb~)yUzjSB6Lkq;1$QKUm%*)7%Ff79VIkGL_A4$eWXKQyCN_%ltK6c$h-fyE2~fOefM^@s72)MoI$#S@bbzRtI4 zWga*nD(E{so4y|u)g5&2&IFPc%gh1WHt;S{zVwFZ{-ewI^=W?Pb(8g`vqa!LMy5hY zUS?tHA?F&4rs!p?B!pdFi1tviTclK?*c&+-m*V40SZ}(0!bddBcHM5a^ z&)isb$0=j+qptYm20p6`fSd5uG+S6Fe;^>R@pcr~)z|xHa~;l0-RX9EN4YWB`5~xI zb{t^^xhY+Rt9zrZrekL$wHaZ2^w+n+NY-`8!A;Dq02-v)pFMEkz~$s>e2J%}Mrl|E zL^Ppgv01#Pz_&H$G)m(k9!Aw=NG%BGhk9LLXASr(%qd%OqYV*5Bgndt)MT!9rdY5A ziK{0lV*Ka0=U#nGw>Za5=y+S>5=v4bv#x`%;vHLW=bB^20 zNovx@?{~^zH|39T!hv>khxcegZSxAIt+(eq-5*@h36Zw5HUWGk&HmZdOfP3(jp{oU z@6PG0>2IM|3gHM!uJ4laytyTyhSLqqPPJ5o>2yK#X`RWX_u+L1CsTC7C` zS&W{qn08wDzF-k3`-_YoU!zYo0-K7Dg?PPEPZrZ}DPfa!bja!f_+0jh5O!OS1+)Al z@Ve?8p=)~?Z91q)(QZoFyYE#ew8liy>z~p2=xDnkuZU;GXnOhexIeCuQBJ>pP5io7 z1r*aK6UG>VxRD0^55nXY^8z-r7%!!jTzh8?u9*9sn=a7{McIEK zD?EQR!w?97sL=9Ub&fGNc*Ykg>l7jIMyht-laAguZ&?w=^!fT8VO-L~!+7Zs(}+{y z8;Qi5aVfJ;fmoj7gj~Ls(N)%C&96Gc>w4kFVoLin)(;!+a;#w|8`AbK5O7^#G=2bd zO{hqTOt7#B7lHWS@81{uz6TgaZw{N805LhPu- ziVvVIPDD?%5|$x^d+Qyz0Z%gpK1)A z!TWwYeMl>tiDnRu7M%Rppn-?AJUnay+di2#G{YZBs-M$-{~a$zK4l!z3Q zUV?Nfj;iX%qNVQ7!sVMWgscfH7Rqk!9^DHhQm-D}s^|9%z?17!w2`rzh%g!(P8|S+ zG^3A53MRA@9pi(D3bd)LI^lq@9rn>}U;i7D;Mq#;9Qj-M^B+yxe-w8AH)M(bhk8hr zWhYFq@?wLq{=xp#aL@lS$!iJ-GfPa;ysW#qU*UQggr7zH5Q1*Bz=REs_rCwpU;aNT z=KX*8;aIg+m7te?>Ia@GG)|inNfOWJq0NF+DMwJz7N(AdNshnzuxT^( zB5nyp@h#$3?H|P!lyotb@=}dqJuCiMAzG2MRu!0=QeAjLV0ZgxXHTGb_Y8(wWBoF; z=NF?FDxp0v>-V{N2p>zaMsumIC;$pzdZF^A+OqY+e}0UxFi`YCt}&3m0rs|MSA#?P z<72qcIe9FEpNd~DV2_`Egn#kAoxqM?vwt0@Oz`H&O0> z6px|b(qgPb8ThG>Oa?Gh zb)$}0>qWohK2MgO5qIC-(Z%n<0o~YybeZ^{i~7%<+V=mQcWMPT7ZK8KP__{bOlT>s zHvyb@wdO&&w0@A8CBnT2=H})lSJI{zyMz)^QyMxo&?E!r2AtqxX_QM~aoqTeN1~Kc}Kn+MV=b`!GAhG(hw;pkwcRT2?(U9A%pGkn~(!)Pa6+uRusX<+n z-;@Zj=`MC*3T^1QGXczabVZmxiu4T)x#$kv&60rQbk7*{KrvVSY7{-#gCWSW?i51L zHuvMM>@1W+T#bY>3Lf`~ci>T6`SOtwHxaMSn5_%Dj&gVgh(<=?)}TwBCey8xS$^*6 zXu^^%)0^(SEL)K^wFYh1WWahVNlc0&oOrTucV^pL9Zm`;qViAnoQfAcegNje3gpFR%^5CA9qd zH=8r%1dF(G!sPB5i~%^pKP52mmRAMYC~vem*@Z~$^qlULfgmQ!CB9k?5=Rz}Wp}f= zuFaJ_+QF$U;;G@3wDiUVQquhwovepT_(5pC3twc_W1dnehuy>Ms287g9bHWZkWIb= z`6N=#IS@jYy|PeC?w?7>T{#2Eni#0QHwKWTVM_wNI~g?ES3VAT0SEOnt^xdcQmBZ-PB;LKgl5TqW@ zlv#`~C6|V*__n%>%_!7h-zA`zGkCZC%8nBJVh-kO7<|xyQY#`6W$4{`BE*}3ntBvh zcmWMtgBNSO+E481ZNmTs(H=!?xNIpEooVRy?hs9qiERGj_c_SKYflvJ@|?)tT6x-5 zwyJ_S=LZF5CnrK1Vn{S9Zo21|Q{Q3a3gvQwP$iGvkfhb`c&l2wnMj%2z=R!A3ANtj z$wnlCTQr&@@{>5YFwZ)50{ACTd70%|ej?~e^YqB%DuDQkNo>b8b3zz(r)VUag9UnR z-v54%qE90NZlT-}{AKxygJl-qpVqKnr9qwn=B(Bby)fHyC*AJaS;Q;1!^W|wC#VPi*K z;hnT*{fPHDFht7Fy52DN6=}28+(>{rNU3^0q=Tp*k0_t2I4RWI^TxfBG+WhfN|I&rhLvT%fi* z>FXW#J4ULn9Dk<0?9%XBTxDe!(BPpApXV{nOgT2g*U)H;uXO z^4$Gd{YkAyjp%MCqb{4U87+DTLBz@!*+EaJcBA^347qR7F!V#d_n91dOqo~`nO}@- zh7OTbk&7O#^>eP7u-QT7z(MLRA8G0p55c=9Op{%T07G&*iSD-W*(QR>57Vs}Zdwkh z@0n*j4EOvJ6+@*ZQV4wsV}OGUWb~wBcCE5)f*5npLNAW2vbWuQ{dn@X91DQ^gLt~&+T^;b|jDA476Vsgk#3+oR{}Q z{Mnv%`;qim8$??X*9$h@J*|=T%^LCu6%EH1lLosy2_z$$!@s5xIPlfWhM(H9TqmjQ z0P`P^y0fEe?G-orr(3y<7lr5kQ97PCEtC-%R_ZjNP9OZ<#P|b6k-VYRQ-Q22ap}v!3d>_#bs^#lG6t!e=_69t&Pr+6q4H zgV&iIq_{2IJF=L9fkRR`t2>Z|Lq5KA7N0!0bhl6L7NYxAU7rrSx`>-ZF)#Ytc?$DS z@*tT-bFg0Cs;7X`KX(KLGfY_iJBuPhO9GrFBQik0koTc$o9k0PvjCJ`@XeQ-Y%+b{ z168i*pb44|#mTLZKuC)re9=lXcGYph1|vg9FI6q>CPI~=7-jWAs1sCLoM7)jkTu=< zST{3A2(2D+NF*_N#I9HU4tDdrX{#sxdVGi%8E4yn-BG>%1L1}8^O+C*vx7JtLvM&z z$ldH6l5w6KMo8OZcBIuu%4w33p(!mQG0&2{oCO``8D)qgdVihJcMzbi?8W3B=nn&_ zqvzL;m5T<=pwLN4R?wpaoyi9VTnW)!J^5l%S?*t*^#VZb^i3UT)Xik6y#0wB-?D<( zv_`%Q<8UF*p(UeST<(SE@*oTN(;s&Lqb#`@ng~ha(^~(D zWhrbKC<-q-%;pQmmd3wK*(@gqYI87OaGEKmZp|i6TM^GdrO)6xPG)g;s7LMy&>P7F$zhnzB!6C8lbt>z%e=rOOyjk!|Dvk;a! z^YCG0E7yYTdC!U!hj!jryKeQ`)l2uq-`K=V$2ojc>tI*^x)|=W@&e)8_%3@e6sJ<@ z#OZjpCf?MUu2}MPvr=Ex$>m2TCKYtrN-XPJZo3@0`h8HE%jx1dV`JmCWUDmkmVmiB zTqM`T2{!4g2_>ZP5wmPHUnjQe%qZ&fcsd6J^sXYG=;IMN*vm+>lH-MwAMWNr$mQOO zeHXAHJsR9!K^{bxspbtQ^M8O8mk^g8i|f+C2C<8veT!1hpFck#Zev*b^EvEevITZs zn=se@3bEFOwh5rZH33k4UZIILiK32je%$#^or>xq7sC>&i~@d!gL~79xuM+Fsaae` z6REi+>@)WL2{4UJYxE2VZzrlK3?UkA+P=L|CkwlZMl7+`<(8@xHkxP;VQA1$AL_pe z6>F>MkuJ#fyj(LfGTv7*JVh22xsF3KRG+x{Qi|^YO{C$0OPwQE=+|=6d54BNBI*?@ zPG5oBE>vwkii~Wcy(q_*&%FNZQe9PLxL?qe=*zE>voSSwb;jfg*0-HW*HXbMxA5IH z(Q4&<%eN+F+B5IV&zVI%^jRqjmGLEKI3&_=Vbh5y|Nei^6Q!p-aZ@&gGL{ABB&V%mxE4LK83rl?k;=TP?8^l6%OpUDGc(SgXW< zQ|6MU2{-S^g>_Un9vy&QL})~TdK%*5*qoYGzAY3`kh=pClofwM{a26|931@M0e!L6 z&y{oVEfGOa?BjpxyvM`kOrpNa=tJ-w$6ua& z7Vb{VmSO(p*g&Bssos{K=T6%3R#9JHA1kelBJsqxZ{IGtOG--W=j7sNPS@G)xrxVO z`kjhxIn`A!HMRo0A$+%H@qW8$yuZMW_i$w66}brT-o>-B3$v$~z00Q%uKPa62H8X# z>BDa+VxXoxZ?oKkdi5{xM0)*DkP+Y9&s8XEYJU_~vGE#HTRqHx1`*!u3~%$ngU9X( zlsU|QlSZHG2Gh0|OOgtmH?b8Uk4ImTL0||^lu&!YaFFg~g$hU?tMG7x6tg|4c<-U~a%bQ9H)qA&$D$3ZxccSGpndkA-ioErj{V+nEQDj-={OqVQ z16!nm58sGgo81IsfTwbE#FbaN=a)mLsy?IINLjqJZCe6uR+RoaF;Co_1-v@5(R$oUV87?^)OP-pnX2k% za9=hyHt0Bciid}@(VTuxWV=@aL9l%V$Ba3P?-S?V+!y;k?d3JC_+HRk0%t`Ug-GXS z$kZkdO&^cXAGvM8&BS|53tJqI4OsD)B|m7SGoua=vk2_kV}3B6Y_DB>NZb?pPIY;% z%?2(roCRbgRf2h2lyk4*%$w)1SLIB0mWHTkA`ju#lDymKUe;v}})Ri{Z5GHqGwchbn;$yej?JF;EW36%`hpu;mQ+XF8 zD`~XlzN{&=s&8l_+oZjuY|Anrkc-JVcvgb#aQKfpm6#lwNP}d?Z=N%;C!gIfDJ(1d z+!TuVFms^3V;Vq9@Mv{)bx3Z7RFzF=Z^JI&q3dys>}l%QcAK7#)ll)i8QRtX4L4vlmUnm{PG6W8aevyGsxP9v0!q1EOzUbF`9C#emH+%P&Uyz z^mA?cehcnJ`O^n#z(q!nx|wpL&I(QNtD9n~p;T2@GchsQE}HXcg))2B7ZdJ@8e$L(k>)iX zMfeV4`ink69YIvsjjZlLJaJpUgZAwZlwq*4uI-S{?{hl^Cb7M$dh+F()mkgL265sG&L_@PH<%I2EGswo(&&Ga5u&1+ zHsPlFa!7R5drfk5{I8YMQBn5(*DwFE{y!i0pL_S87v*oK!mEWsb#*zz$1z}EvkEb>+kN_C`bP1r~mr@3`>OX<2deoh(9Q&6HU19oxqRYu)-fy zk@pW#?|TplEz1KOPpVZa0&L6m*P=K-%Yi>`ywInMWw@XRzu$ndaA)p2 zf4v`^c!WEDKf=mec))VMAFzD|WmWE9kDn1Q2g~o5qgNR6;hLJ$)laAtmj3OZVj=)0 zSN@z!kMsSX{^&mHee~po`{S*X!8@t8rjI+z;0AtNOQ^$&e)b z>r~HQB06Ko6^k=EA%yhn%lth0=jVM<7G3q_O$DX-&r7-?+kgN{jd`;T((fBXC&KU_(Qtp!LG-i%izC5kg%UQW*y15WBc5%_#_Dcwz-CwCdxeS?Cc>!5I{ zv{S)f%>LQW-%|>t>w<1mQQHIW&bb_7?62M}J zUoEj3R z66#o0#)h9dzaf?WuX5k%egMq~5jnr3OcMq{2zI-`N#<=CJ zt%xzi$<8@6?OMbOhd z4h_TX{5_*3yACY-a_FtZKZ0js4Fy~Gf+ORA6L|_8ef-b__s_m5uf51FA=v#N#8Y##aJ8U2=UcJ1Ig6+S8HsBugEstW~ zu~F*2bv$EVli2UI!mB;2>U-7ccpdF-%=yVhb?sAsb1{O3Az;>@k3ieQc zrr?9&a9-_f)o?I^lqmU!9A`?-X6)zM#&+-8pIQ6Ib9Ga0+#!MfMvO&Qrn_U|iKknT zxaDW|M)``~>BFg<03%XCAWsyfIv0F|FGB3D@oUV$8KvY4#^A5V+@lX!*-ExoVxHXV z_)b@tr8+OE6uvh$c4@|p?-dZ;Lo!-rG)Ybijv;MHMn~s1-4$DP{ocp^+UTx!binsb z0R$xOWEV5{48Z=+nrScwF)^_(WZm!f9{Bg^dI}HsL)y{urb~7#Kzpvq3u}$oUDzkQ znR(Z)UDRLM3b2gch=9vwJ_oBP!K0Xn2vvQd7$6eiks;=Z!6XKuAMI{JVBBi6RM`uD z?8h)xORAY#??e&V$a7$>SO;=(JuX3G>ck#0aBP2q{cwd6?&I^rZ1?7FJb(IB3oMDf zSRG5a2k+nW@F{`ao)xiEVB{}FIc$jscv~@o6Hx040Y`sHJ9_~*9iw(YPq?yH${77K zGJm2ZPse6cKk8h+-^0bK^#}2p31k&ZUZN1^Y;wM`FWe>)yG#~909LT9c^jbfbiuvy z?-fCwB6T`;5E=1{Su}PApI;DE#M+hMrZ?7I3egGY)K`nII-|H1Hd6A}WK{L2x8t;d zFt9y$?ASw!^6Xm!43u| zo%-04388yu10UfkndlsmfL9ht(^@S8aH1-q@b!Hr|f;4{jUWUgpb%&$B_vziwX{1VVAbhSYOb+o6L_j*W}uW$FP zMRRz5+I|<>iJe4sQK2-2DS{X#3+}s&T%UEL6M?Vt4L-6~!6RC{k)aa<&&eDN2h$GK zdHehOhla)#j}6q7JKhfI`DIpfZsE0|tb*zX#-jQ*-eJ)ej(?n47BlW=7C5QjYk0eu#AD@PlkqN>>Jyo|*l@ zXD&2r6c&2_aclmUOQTbRfGRD{)Q0c71&}L%?TC(!PDS((X3jGZ4l*y}IF>~h`3Wt6 z-`wML;PPm9=|t+0BS$bk!8g1bR9JD*QG-(9BMa;QaXrGHDUkL^H27lD%Y#KY5;5lO zc^Gf)=-!&1o}N?!TuZC{RwWJA!)DUa!N1{Pell);`UK3FeEI;L6{#?5UEHUk5vcXR z!=tWA@J!M{!OwBpWQ7Av)6^Q0jJn!E3!F&WEbTCr5OW!M@X!wKut|gNY=+6Pa`}Jc zd;^AqVx9N-;}V3rJ3G~vu8Z^!dVHChj3D0X7QN8C=XgDZL~-4B7g{6(cA3^}3pl2r z@Jc81t&Igp5`ecndkfktDZ&4GF!wWQs-DO*_5?$B1JknO&lx$TO|pMzBRowg)nM?b zD?@Mp{+pwEUVVHjuX?W>^%d0a<kD>ukfJR5msh_m_2YG@(wkT!U;f)`qnN~R+N;Fu5pOhAJ(fg|qBAKbCy*zGvfm^-7aYW!VyKTD7$P#TNd#qDn63KN z&k*CU%L1~XZg~v`5G-53=Qo$YPWI6fa93LyREgm`T*&E&{Vx8~%KQ}S?I%BGzN&8yRi^gFV2QnaWd|R8xK{pDSW1$LOE^j9km~qHpySnsoot+{p1?^W2c{4$*~{y#HQy)e&Y5OtfqbO!%{u*GjaBq3AO!shy6kVt)}}` z2vTg>$#R&Uus5iaKuw5PwI9^}lDpXXiHFOPW5+J9{QmgVF;_P?y0v1SBl(N)dVW?cvp~%!Ssk~ik@EKPkYrK?7}Ft21Vbn4rMhS$tV(E`EGR3}Nj3F( zs2X&jcexQ$@RQi~v+K6_p>k@GX!PM%)A-7EPvr--C^(BWr;JYx6vIdohXYTYJUPZ^ z!97tl5lv>(!rZA9m~(pUuI!&`SN9S z@HUAkJI`!nI4B;0jP-UM9_{kmqMoo3UJ@(4stRP?-PItokGxYdpMC!9lFdKw<4b4r zwyYMuJ*+Qnx-l&pugM$M7LpyEboRqy8O11n8fyq?3srDwzD}^?h}Z?a2p=<9ZZ<70 zA<>{y&$nmwUB~hLM_qzwHmMQU$1;f|ZM_A>vVfn|?&{1rCZgz2L0=0%Bq6llK{5Gr-Xp)-r%I6F zS?8NvH;*VP3aG_tg@0ieQT=*e5(CytXM`>w+xMd?i63~Wm7XLR-gCWn-%6I9lqigM zb5~huqdrq%unX zxFMsfye1Mc%*16@>_SEErfP&_`y3Vbjr+@8BX~Izot%NtwE4Js^C}BwIrlEw4)P64 z(69I0sX^gBsK3wY9d37J))An0L(_E3f&!|+CEY+Wkm=)dA`KU zX-r9%_`_)q6X-G0^<7$Nfcbfd>B#!9j{!^%>Q%uaNEq-J1A(77h>j zfAwAmsfTY7!aVFMh$E3q<8sdEA6Hp9m|IT${DGn!JUqGf@AU>R+wxT#|978Dx&7~y^b{${AM+liw z$2-F1d%404zhtd7kLAbJwi7X`4B3d1^P(^ttT%`Bz)#(;BtucZAD}o;zG|51?ypLZOyG)T=J2j@S%+F3w%%aTZ;pHu!#W<0mlvI=B$3dDTv@D3(#let} z*do(TFyJh{6o2eQQuGE_Eybfp-=VtbYKPj|OlTHry8Z&q*B5rM>wC0CMe;|oGalVIyK^(|_CSC{LKsr8T;`kDh&C)E}Aa%bQ;0WyuQn2@!Tk{i)6y1G(70Gm?z903!t3|Zf@3Uxld-8 zkn?>z*td#=`1@~LK!P3v-R|p(*J#;wdcUDZ)2IXIh=~G58BRqdCnXuqqc1ahiyAel z?9F0p`9<>7g(W4A&)bD}I+pM0pbwbG2N=%7CBpEn!}Q3=Hmo8oyd)?03EGNCvuh~z zs2>{WmBGa$0EPjdZAI+{1QnRGr26 zUd4fM1Z3Fh(Pbs2OqF(ykHkDTYp5V)fPn?Pb zIiX%Dv%VYk^rZ{;6lEbxmmG!-NUeku&I-PS*D^j~;mTizTW>?dCAUF7QCm zGbCgO6EKlPo7*S@Qn=)L6j~u$*5@qjeXe=%AN4Ie!&9e)`H4LC3vc#`^O{pv8mNCn z$CUs9ast13byO*aMdGSqcpA~`$~{v3xg9^S|{Quldt0H zCiu2MCmis}&x*oqJSv8nKrXg;ZJx)I8FWdddCGFyVz7s3F$_urOLLpS6ZERuB?y z^y>7>NG2#2gKYLPEcwmk&9B7`CHW^0HMb`8D~L~V>WTaPnv;z^){T6~fS?R^xq;VD zl-CTSY+BZG9_>(!XZifZq+||XlrwN2nZ0{kvtAglO)PKGD;Ij@ToNKR2@z~fA2bP1 zpFYI_F>lQ{vwknaSEj%DyU>;zYf(=iBTaMyIvMJ|mD4aIekqfU6f`likHHYZAi^UT z&R}fe&fzA1Rj`O$`f#8VnFGvLL=3Rdw;CdZi-bVjhFCHup&_%m7jJv8nP$RS=TV~* zPP=%;*je^V-q0GspQY-6x5M<&W5-r%>!H&KF3x~7SMR%;)4)fuOTEWKxTe47?17fD zDm@MHJh%02xO*x`wt4i($jBIdv{*>I?$SitzN$PO*SHVgb|`QP&zQ%RO%n}e8F}Sw z&gwc0yNv1#GP#0&UF-ZCY+p;wa1gbm39M@_OD^BUH8do2t{_D~0z091Xr`@APQy`{ z!@7o_Joh6DT6So?xrhilq5SquA^=kYaRSuIYwLTsK`L1OO+B*JI23DAPKn~jk4vC_ z$TBQk(-0Y{`sRG~*7P>u05qj-X%;~-yEbp$Y~uMd_ua9iX=`RTW}%fDdp`C4lOh7X zyJVZi|0I=^caoYYHgn2|6D}M_+?aHRU`7$Ow1Zex=xy(&5Z~Pn(Ax1x2z;-|Ui7zh=CDGC#s2uDuR>Oe}~6B+6H2sEqE0=RwGAR9q>C!4SzARb-wu7qXg4$v&q<~NCPKcJ2Gl0YAT=F&UQQ2OWDvVdLk%<~XyGObw? zb8|_G{kUm}9mY6NyIlX7aF3YzUaIGO_OEOMG)2_1br!{urw0O!pC9u!>GkJOA(1w@ z52j)L*jg}hLOTk%McjVOB;c@u0<8uq07KFB&$I*OFchBg&WeQwwMUV^;+`i9q8R}l@a!3RL4-`!kRrl)mb1fEcgg*>Y9`j z;DGewwW2fuj+8w4y78_1KP%fO{?S3?=>&?T^XMfM5oh>q*W zirZp1yo3ypSGY}xWVy`P7D{IuT7Y`G3?jRh6&4mAbXpO?aPa$2l*%c7=_n{;b7(g4 zUujJP;GQSV#u@1$_SZqZ!IE(CYYyP2bC{MZW6aSjG=7cLcOKCLw3@Zub8B53Vw?0e zx6m3c(I#6h7NZXnhQ^Q3aox*o=~L04XMUb`+lgT($xKfzMI|NMI0&0H1&gxtJd$55 zlYZfBXlU4bsh(yNa1!`b>de&6LTBtPA#wt!lAJspM+@a(@8UxY0x8aeVCzhd%w0GV z9`20hI^Rx{ZTZbV8&no?y`0+>#?Miw4y5*kIXPCSAbgChR*7#((7P47@ZsD-u>6b1 zj~|EQFbu@=ignu#eC}g2{E3|`sS4>^@Lw_rlHMy=FCJ-8d$5~qr<4@x-+m z2n8gg$Drs@C&m{Q6+L3K^6jYBM^`aqHvU>-%v-|~*kX|iY2S59N=uRKV%B{VSKd5~ z_OIT+v%Hdw7_NxfVr{K!EhMs$%l&A7F)upfHEY)3RvX!)%(os!<&N^O0U1qYiiaVf zx9XW&>kmwhuDHI0>}?N7A2*4R<$BU~uVQ?_?$nTt710CR-+WkMwSN2tml`#z)a96x zW|W|r4ycY7FZB`HzWqpf@mm1K0Sh2QmvS%|V)cp0Fs7ktXtUm&e5SB2MAqOFeLzL7 zDaIff1G3OREtbDRf35sJVxN>GsxC$Rj&fDK8xULi|0&COKxe`IGdpd(Zre>F5WemC z?#lPi3%UycgQVh9X`T9Wj>sN97AoB!L5Ne4>Up~ggp^6L2sd5_I_MNXukr^2wDc@H zzhDW31jxw}t!&3RO#7Lva~#vevr9fo+}vS~+kp4Q;i68Gp=*hkD>Saz6N^Po2^ATu zgj_|BHF#l^>>7p_AcvT_zvH8INe`O+9AbQxQ%5T6r(Kq%n@!WVzPn=iZm4%;q(DF; zo4D%7U!jA*R;QL}$*UMmT^bvU5+p*%FCyEW ze@vD-NJe&~%_VWe_r#s3lCQL;POO?S)_u&mYVDq%udVRD4rqP4AcdrsW~>^ms${H# z{YVr3IMtCouBpTj@a;~9CHa4fc+P5>P*=W*XscrUr44^9fgDz&?4a`Mv_!YI78ZV~ zCUQ-TzoF3tURUPf<`#|iYxGrcFvmMi^^N&CTX=XH)C%8^t@R?k&uA+wcG8^?;B&hpdlDIc=ahjz$F1{~_;^iU@5g*j4mXA5?Xfjcd9;zidX)PDzM zG$gooz0+qIF}JIiOEX97ZWCp0Q1J+W35Yl$uVocX|0rwD28(&xy2yEO#ws8Gd1$!> zw>`lPF!y7!?)2i!p$%7>^<*PdUL22jQ61Tja6|caIBuveK1`=M(crGu?5_cp6Z?C( zBrhF~!kGGoJ(6bi3{SDx8eKYy>+@B7d9`RjgkUDxOQoa24I$8j9* z??yK-2DpScRL*p&uQWD(Fh)?@;X|j^r8?wt*gTz0D=(P3a`T=#(;K@2Wr?K)GGkdR zDPLnNr0kV~|3DBmBX4#Z?=>NO@W2?#hrd6b@I_vby5U2cuV^TAD7$;Ic-`J$-G^$B&sNaI6xL`3_XYAKiwNSsIl zo}nVEcmZPGFvMVyFE1L)7Ip{2D@QXK6p3>zgynx>&w6KZNp9}f#FYqd*Iq9RALKwz zZQwp?zflz7eFuh~Jfr-lIJTqb7E3M|TCA2|i6~?7Q!vIop2A;nz4imOmPp6vml0JO zI1SD=NIzCA<*U^l^WZDF$ItSsF zX=O?nBMsbq``|s0ZOXQbvF0KpVz_4d^y{gDjSlWK58d6*YLyS%5MjxE??i`V9xQoL z5GGFpGR6`yMwb94`z!R%b+6q(_dJ|!4UqJThYy!@;AV2-8^bJgCL-sRmzTG93cJ4} zk$4EML!A{yr6De@qmfUWFH(pZ{Q6Td4` zRDgJKRkOTd8G(d|zar6}|D)?y;B8?e<0PXbd>qx->$YIMpo0YA;BOQ)+aPx1*yAsG zdCRJIG20b9;w2p()FebjCy=@P8vVSh_U#G(C?s7*AblZXw7DPv#tsR*U$_)~Zz7U6 z)hySlTn0kQJd~anK|$;<55tOBGfwayI)TOp`iHz)s42A2KkK^0rfD z?6l|cnrIAbn!)g7(<+AUKa7k0UkRw9lJp@i8!)f(3JZnAePh z+={&2ytJ?VDQ`bNag>>C-Y6<4!08PiIQ^e=F=ZGc0PN#iwBUAO8}9BB_|LJC`g{W_ z!`n~3pnU0u+XKl5PTO<;`Jt>%tmET{4}-t_Bo3KLi|m#p9EN#0Y_W@&ZdCEUatsh| zwVvLlib4a*yn$1F!PV*}aR(7}2aE6(u~_f_m=P+?Se?9wuppiBBQW*qQTP9o8+W!v z!mEO#8%fj0<$M405c?NH(3rJDCd9k#Co&C?@b&7-|L?~*cfpY+Mc8;#7#RdxXV#nV z`_IZtyJ4&NqR7+VvVoN~^XxlErF8!P%n@aM#F?Zh!n#Z#<^=2Sd&?^1Ka=zsG4C`8 z_?s1T5&Xgb5;qu;|IZ_z2%w~O>((NR?Y3xw3Ge@Ce|p(`b4$gccJycww4hhMZVX{H z$`}iKdG5cH$>I6Ut-QSaubIf2W*pRcyV`dHXv`%X^{^m5o8&<*oH>ND&o;>eyF34-n{fHl9Q9c$t*k11$4_iob53siP1)C3r+Yt)wh?kD7dvEVK#r0jbzMB zTiGc230->B5i5->;JoJ;vx|$T1NG8xy7%1sMP=vrNc`tyWVz(!=U;5dNEh=Uu*AVr zM;HBPEXE6=4Z^1wgvF{#x&FE%)|c|1*KSOPkj{YsNt|#)OP;9zF3>7C>81KbFoo|1 zPsvgJ=OGL(Bo^rRt%^J&Tt>~c^FJe%`bCm0QR;gv-mAy!-S3F?+VY=K1g=Ag_fdF0 z8Wz1Dl#)Z;ao)5td_(NRr}z-Jgs`}K>3{9tEjf94PyJkY3qG4{@h;=a1@@RCisfs{a}klwnQuEqOR@f}kPo_^(XNM`U!^6e^{ErqM0WsF1_JH;6&dS8K+0OK_5(1PEX`$@nfBs}%sZ#(kr$)=?Y6UZ3w7QO2< zn#)5@dp&*}E;$`{*Dd88+&xH%t?GPOD;K;&trKhL&Y!h80e_ZEs zq%;RP&(i!;thI001@wXc6vQm9SW@g+BQ;W0%(Ad?@l5)_e_;B3Zt%}@2Q*Rn!8OsB zh)cPl=_4g$&ZTZ#4ZMVlSjY9=`no|Ws+O5`tA$GM%nf5Q5Yb5gy(AUeSP{Pt z2dbsd(IN&Q9EXnMjV(d{jMP~fUZT7HTSyH(-L%xc56LE;qYr*^%uQM>2jFP_4Nc9> zM^-M%+Nll&a@-VQha5a_{gX_ke2P$itK?q`I<*+a!mz699J;z0Su%<+&%Kbgi&%J` zU=7mcmn|t&o3{qIB1d!Kk53##Qj2H$jzHtSwfc*HE%_&?wXZCODgbPFSJ!3op0!F! zO6c-xTlQS)m^b?7l|=y7?y~ zPL&LDQhABF()`sq_p~&ESVVrg`Q8Glh`0-sSVBf3+=Z;w05xq^RPz%x-!0BS6$%Q` z$Gvki)t+SDt7(yu0=aW+IVrAxf02?ONtP&rNQ+~e+A9H{wdLQB46Z_kw&m$Xbb-Mf z1ey+Y*Hrxb$6pLVK{vOo9JN>S<1an^rXV9EC{F9e_xt%F3v}SyldqTS>gwiA`#*hZ zU`gTBnA=ImWvO$K4m*!!IC>lZQPw22?)N%5?_R`^Wu)`i4y9($Q$punneyra)zh8l zZ)5w490t3@=+{;TySc@6-egU^sE@6xlYozKJo2RefnYOiT}rWEi4tZ>lRPB@clsCrnsr%skjCI$=p67n14LT;<(8HF{c2f-CWH@u&ptJcX*YSPXPwGY__Me?MK{Nph^12!8o0rL#bpPE(4GrZV3+BvHl2SLqTET5z@BCYR%*v z3#hS$fJL(pu~F7)AafgM-T+Kz(Nl2WA3sGZRzPUGG~4gtoJH}a|5iNWaB`^L6WB%O z%VLsUz(8NA`{Mepie;;wTPWW}{g(%j9Kxxyf7oVy;ws`1^RCL{+lr8IEo3< z4f{`CgRB-tpo8^WK=BiPFyK>74W^E(mj=aH67W>u5Un$bf z9hK=&?)Q`_5L(=T7t zw}>nk2OcALS1dHasG)w4lYw_o`8LhM8w;^98&~72TZ2*6RN>0BxScfbOSLS!F1U*Y zz<|T-1UqNs;~9$N_*z5AAS;xB{yg&lI>5Y?$Y|+apxASe<(9yaZG0%^NwTZ3)i0h$ zBX-GJOIUm0EbbQHyz`Kx9gw6Y!CbAZZBFmRPm^X6c zw3e662-sD1r=a+R-K;Qg93*e^xAS&t-ttQ1^nMTa`t$MjUkLjX zfeW6$F67VW+oC?c)?yP-rMN*pQvRHxK0%AWZeZMC*2d0Tck4^od296-?t3|JXbsy> zgnb5NoxG6zpL=D}0O_^0S_}6X%sZTR59{oZiox(s%{!VBgRmTGSl3XP%zqmdYuVu` zRA{gxwSE8GC8LE<#qgOmpw2dbE>fd#Trty%{?aDyr6}=`sAfREfxNZ_y(JLjv*#OL5 zhmeiFuI`#^htSc}4!5*2ayAHK#Lzx(IK451IP1h>juJFBPthVr&;44ulT}i%YNi7P zi0y!m^y@*xTbD>flrB?lqmGJ;Vhr7&d8OZELfJhh6E&ID6Tq)AKH`zf8!~ax$5UiXyjSH zU+KDH`s4J5SmJyUi{D7(uZ=2Wf?!Yiu{L*>w*Z*swY&i^yy8ie?ZBbxKsj78((MZp zgcFEze|`q2=>pUY5uug8hQ{a#D7JiFS7q4RL>3QOdVsFJqxnNgE8xJ@NIbv2h!#)K zGC_yo$Dh^TnuJE=WR#(e-bwyV64s}-!Jkw_dlW>qOK5{H;5#ip0K_FOX{BK-a7w{| zlBld&zUA2Hp~o%&nRm7;5^%i*?8wb;(dS4Jb>9FJzb4NBLDoDacns_yL#?f6cA~v6 zX)24xd2#oy)B#kytw0O}y1i7XFX%UkC4-nXYzPUpt7v&iL;Jz?ay6QhwgykCz7mcA z2kWwG<(i&}N0F?P?J~hpqT^xr`Ew@MuIcK*1p;4Fui@B_8F-0BR!Ny|=UDyOiRdaYpnkS+ zw}6`9S&dw;O#3ltT7mkb4K@*`hvV9n%qg>{-%?C4-n9XYAnb6feI9dSZqulEt*W>U zB}NiMwoL-8V2(VIB~yP)u7X|cYsJX$4jdcnN-3CQ#IvqyS=&cHcBcUf zS7F~Q&p2!??r<9r02E*{v4BNRkxSR-0t^;CK+qfot5_43-P(BZ1xS~R?gA`u%@0T_ zlcEa#>x(SVVbs-9GcJkqGW9Y7^#kymS$xgmz;>D@NS47(DAH{)N*2FnArx2{mf}EE*@%3P3V(j4A&#@}cQZUKLwsQM9cYWw ztDrcRk5tOEayvkw@hITLRlaosyh117)k(qqgunU<+0l{q5_S#_jtk2{aQKN#vWZFD z^a#VCw_9+JYVSC}F3Wt6QLCY3x#lW0v$$o#gKpTQY3LlkU-4<>oVR65y3^*jEyb0a z+5Y<8N*3AUnHgIIXNHq9VF9fDw5tl}yt= z6Kme^>-founH&x$Du-i^rd-=)4@on~yjy6pD%;UfDWc+b6VR>p&UY=9PaZ3AZB&+u zxv8;e)uNC5$|o0j)r+!8EnHMOJTmrUpb+T!BWKTf#>Wp>PQPpZ{4_pZUvH!(*(lsu z&}~h^7u$;Wm5%i*Kki1>4sr|n_j^WhDf@X_vV297bBRqSic#Z7MX15ccvFLvZ4vDw zhf39TV|A;qXWv~j{_-Vi0D+=w>L6oJwP_!mTnBnH|Aj8vVe$8t2)ZMapZh@6sF{l- z7+EvO7BF_ih*z9WQsl@$}KIEw1UbFKy(-Hg>>Jp!@aYtQB5uF+K8v%M|*~A{* zP3@s<>89dS&#QwxgadD+eM6lcx*>-MY~7mu_^|^aPIV4#dX*!-QhG(k8XoG{hJvRK zxesPgJ+79TJ}PH}f~jNANmF)slsC{Fn_76>0L6GGGU3fFUi?IDv7K-!zmDFFgv z$ZrBxBGlKM2zN2b%R$FpXCLfpDL&r(( zRwQq#CTv@BS8=Um+0D~_R0b-kRQ89^7U%dElgYmp+`V5UQ2$v<8dV72ctZ%NcPj&0 zY8nMv>*H@{f^=q0?eM|9W?dJO4$H~Kb;35DTU;RZ5j(o4>-LnhCP$}^AcNMl6UWhU zO0^U^FvMudryq_eP21lQWk5_-uy@8J{l_0^tgi8Kc+Kj1Tb?3#vAYDXZol9b%z}0d zS?sw|_U&OahrXKfH_GfSxUrl1SF7J-AFh^ZSWH}!gJ)2k;T^)uR)jbC?;7KcW-)^0 z0&z?u6V%t)efT4y4EquyxGAWuo#;5ghG5;U;5kPMb!t!CQ(U{!C)IdK@w`kV-;!4q}GER+s^jTu60%e{OSaA_T0{u7H0l|zOv~Znpv)< zkA9iZD20Hq&3Q+)*%8TgE`p^B6V<)fFePOS0rtOlyL2q6O*WY?pf6FoO&{WnxJ^WV z0RG6+9*@I1lyHd0Q#G#Ap-3^x%gT;I{?#CbsgKi7H&^OzIiQf>!TlJ?Qfu5o8X1W> z(l2t>UORK1@kcw)0h)!$3+E>90`d&cVKjVt7N^PUGYc?et@%BGtu_~R*xVu)-F;Rh zphJ0sC}0A272Y*!k{&Q1@s4h52#U^#d_#9K#VaTJJ4BKM;icl1tiD8uJ8h@OR?=j; zUID4QF6h7=0N@d`+M;5}k$%W&9dy#tt{=b5Z2S9pp-72-1tX|T7z-QfjNH+$A^ zmGk1%NJ-fA6k?5x(+@$l0`gTjW*So0%l8Js-(V}(BqHz*H7^nCM|s!NMET+RiAo1H zD)Hd>%f(fR$3%_Q;Z`NkPAU5XC67vJOlI^F(gO}7Pt%oGF}^b6r-p0Bt7*#K^%AffS-&j5z3 zc}@H%A^0du6IX_FBC(B9YW8HsTzSeeiifSZWKdw73ZnIaL+%LFX z?RwOL?x@Pi7XnXa^G?7WqmsWrXbk^csS+UTYmr?gSj^6fSYQwvq1SK&mr6*w=7L@N zMZO^Jt0Be?y+((+;LEPKv<^axN3sbpKgI1!R&1z@J%7ls52qNcvRpb`W&|npat{DM z=e4yV<*3UV3dYk7#Je^Co390uENx_qhA zK;SuH4i1kIm(v9J;K;PxCUpMt*sr4UXg4kzGi&QK{!=spAX?bC;6F?N1iE+xF|XMW z;!!^92GT^@kZa(dV`Ed;RqC(r?Kc7g+B6oUg!7T! z5#|#@x+XGZ(2={1s&A>FlAWn$_dl|mdpH{4?{})v0yXnE8xoP#yt==T zpBmiQdwQKDHiX&D_@ce?7jfLT%@BE5rEBfQY+NV-*4erOEt;+l(q);!@2EK`S zkWRE~1{)Eg*pU&Up`P%xr{Y?I*=_hG;GWr<3dIl8OGSrLF6{lTz>@!n_fqRr8afUr zMou=oeddr*gf&Pd1v6V0J<4!3EH#c`cC;YuF>3V&*sjCh!Hyfb#PDRccSM}IO7!89 zaTxCELR=)10`4evcb!^*48l5h3*cMb`YcmxaV#B54_~VoAH1~PQBFZJvDxF>SM3V&jQhE zoYy3#p;9-fDpd;+o=3(jEaJCVX4!ppE7I0}A_S(fy2A&0AFi*gf9lX)co3L`=A=x^ zrW_dIZdH;6<)>Z+{8KN)GNxE}j0b9pQWHWZwOdF+#m(~p8BGPEGSX|iyYFohPYGmi zOqT-f z0|i;xV$~_=jKp0;?+c{|hx`Y4tf1yj}j{zB0&Jp&lgCP;e8jX6JBc8 z2fM|T80VSjP%OVx;_myY4GaL_^t5{y`tP4Rw-1L z5nvF%A;1w!#?kgy`qJcX<=ptILK|W#__Q+A^RW}(@?HGVXf4}wSfBFVHpaCOvff%W z+FAn7yF?#_goain9VTp0z>8tfY#z`PoLv!9^@zP8^dZsbXXiQl*Ba^@0%as4|qsb&t5i@gScBZNZYag|}0PDJJx7S_R=0<_5YvB_xvmB6cj zlkOPaC$Y-n@s2CU-n>Ck9`AeGl!YjM;lGM37P~*JlSE@oe*Umz*fz(EI`GI4rEk&? z-B1ZfhF4yAP!`47wWSUun`{PRn{AWL1IyoA^mg`Pit`q-Ii(%3CAzx0kdl0~T{+)W z%h5Ah4vgf)2#!xry50VFIj?|gDK94{P)FA|LoSCce*r_RDEWY3knk-~&l-GZu9}d( zygeTOGeaxZ&eSljI*1o{U+RHOQVLy85?%w&19Cf0dz_hm-~J21*^14TVmN2|h>d!I zy2IQp&FCIG`C0JGlb*%K^yHGJQpF*gb@Lm|a1FZ0MyxzRwfPQljqJJScC~RTPQE6% z>A1^A%ha~f3bOQK+Jt5!pt6M@5W{MtV@ny>@5^F;4$`MIeu zPDCzj>y|BeWrkZt0>^zFx&Y$`)xR{Zs{^2{qsBK)6tvHuU$SSz9+NFGYFHWFcob~E zLxd#MxYi?z8Eh*bpPDp_YcH2|?BtF+KoDN(Elkkw-MAMArn%&e2vFp z{iiSTq!1lfz{x_AjnK9_f&LW*vw@3r+>Q%JgX&DayJ#q%4EGS*s<5zddF@&F9iSU_ zHD^R$#)TJjTH;1upf_v0j-DQ2TsVX~jp|Z}42}}}RCzY>{VtU3AJzpc%Z#NXZStob zj)qPzp{XzpzGvkk?@0)ql`-GZYED0?f?fx-D-%vg5M^L{w}}qp{=mfzH|(*7pl&{+ z1zlC#u6m%1%VoddisSb24)|ae55t7K4Qx>U_Y~yZ{D$IQ0(E)l%@`(euiFzphg=T? znyIFG$YB*R5qXc-gJmAs5fMC7qb&_Y3TuVO6x(=z=_@eUWSa>b)8Zql>_AO&?vY24THbs6Rwu0C*oKPtK(NaP5w7MX4cquj zW025sM%`@hel%J@`@1+~wU`C<7){rFMrb*u$?Xa=^{Z8eSxGa+^kswmLP2-b>SYVz zIfm9k_@Vn0BJxm*sJ77?MAiM#gWoK8@Aa7EJ>2?Q`Sse>tIr#$naf>lxsdyyvPKg4 z?<*nj1mT@1ee?Q(G{(0hdGY{7C!&RM_a{IK{oUOut#oug9!RIrq}JH)>>4jh_HzlTMgIUKX;7z?X`n#wt*c;&XKd*VL zTx!9E-m|N#O#p<98zuQny->*%p-lP^f|}Fp9IBgg+{i@~^H0ZITa*6%F!H_DW6VUJ z%2XLH5tt%9mxs}BfXo9TJ6+YVu&|42idQUP&Jt|_0Em0R(RON#+1Z;Z{sQ$L^|(q1 zNJT!LzLdVn6PdE{4d>$gW@)3ez}S|I!${{hp>{sGTLNUM7h~)S|6EX6=`Bo$8ozK; z_P5XO7QwJ}K>aHl(+F7f>u~dbi?JJ8@{k4%ubw|joI>LQ@j{!|ng|fwSl;1O8qv9@t>YTAqz?~#-w|_ydvG8y?FhktlFIU8g0O#8f%bW{b zcoz*Ew8zhYIT=%xkgz%dKc%?&Jo@E0)IG{ZL0grMxF;$Q@{0(@wS%-z^UTy zqnY7@Crj0~?G<2XYesJjf5SDtaEq>NKBpK5DosvZ#+&l8zsiBza|4a`3+?Fg9`j3d zk`BmQ4R$d~T58^5q(K3^5dI^a+PwPxz|;+fwVp7PDI4}hPF^@ z(lTnv0OYAxTC1auUZUWIEWD&*X|BV3OcPn0}LG zX&e5E>SL$`JNp5qYp`lpQKoSkjCZGR0VzG*w~?i8&uvg6KJ+k5@?Y`3(Lky zk3upp8ksP2=@RfgJxm}<>g(#HLy2=jf}GclRZ??3`fD7t?5t3F*5MGhf!R4BfhCt? zv*E62_XFoDMmj5cvGs?M+tJbT?G28$!JTY_1jTK<*;zC`YE%-i#ZEd?mQF<*60cy2 zUuMTD_O{T_iRLUrK%Tbv?bG3 zqZvx{9GIQ!?xP^2hWAz~gQ8Vi6MU+nM=`kNQd9^XD~?mNU351!mui&n?p$!-vytMJ zdy9y8IMo_%xYDDQCu=%49-r)4(hvNDK{Jx!rTLjQuVrXVaEKvZjN6n?SEj)32K(v1 zO|wM1wB5clW8wOESC#seX6drL5)z~-h-D}J*z%sFcZgiHYTC0Y$YIltXTY&}zPpUW zXSP4b_-Z@8d!Ezpz0J$h2_&L!z)^rfw>R+(7bi7gz<7ne9)GfiTT-*HKx*(oToE(*I819&?>INQ;bojOcS_X9>SU5<)gh9~9qV1iP~A z?Fm>>6I*KnP#Ac-18#Oge^1vdR?n#|TCVghjKsUSha_jMtnCT_?#fO1?cc+YEM|7z zYdvZVkAx`e9lMF%OO~@-+oJji`5>iSALJHULGD- zu~73TTap#LX< zMpZ$S(6F5^AdtCAl50&$mek8{EcyNS*#6$$CDH=(Tu468ZAapg8ECEqB4SwDNIT~l z)rMks0*<^3{_g0X9;tn5ZcH5rvGC|~!vFl1x(KLGjPL^aV5=r zj7Kl2-y#iwp9`A*H^tjO0jNV*yc8+xe>>~W)?~_@{(KLqTb=>#5U|`?M@P{ikqT85 zI?nx_o_UYzZWJlPV`vKVh9=@lcdqg1ye~XNAD<7KsU1W~Uh!X9S6MT3)I6m_G3NMl zTQKB-xsTeAJ~mU{ylGj*4dYH@fOJ;J11dIIKv%xL@)rMdfZBO(hsZcKLB)rVLii1l zSp>go-X`0uVq(%y(CS$G2fc_xU!HvV@G}?uc~Q90DnI`mtn*fOQ$%LufRKvgULUc^ zz7Mvq6a4?Z&>mde+yzbh*Gb2~i|P>TuRQOz*f8)C`ds}En;4#=mV28(H4$Hs*ceSN zbZM9&T*_8BZw+)Fejodl!%D&;{@uG(GJF-$+~?|~MUxynYr8N~%T;AC1ZRb|@E zthRQUx5iSq&hEOnU^yG@;7LRy#V?>mdfkLD&HK5f@Pxw&q%NJx+Op>may=;N@3)DZ z|APX%Q6RpI+-(AWD{mwQRcMa%#q$=@f#(X%!fVJ<2Cx2zhGL4kqA9EXNUlEvxg0xS zM+olq{-Ms2=Q%HpBE!;@J#Kah>&3mjDqU1BR^oz2!!B&Ew zgwp^u7@oV`o%1#Z1a_KHYJfEeZdjwL&UPXTm#J$H@4VHN_Bg%=jjzhmrFM~Uz2%Y_ znBJk`;Y=MY^Uj5{Hdgd*DU!>44Mg{3%?GP_pUC|M073SrPvn_pxFTANY_TU@yEk6{ zGkR|!ZK4oy;MgC3fg{_$#17#9?6I(UC)5Oiz%1I>%HhHZl;_4S*&!Oxw$++9#e1-x zjxi+pXZ;dsrSmOy^B#DsxJC$pb8rsY$Lg%9=vKT*vReN#g{zvX^aB!+XxP@Tfh{X{ z`0&n}B`}S~%jT@>swTK~mW>WeFzBce%v65EFu;7sR(u(pq-oS)>3i^y|;NPo>;9NC=xj@LI?#z*H{iE=1(~}z3_}p z4^4kLmetxdb4sAjLt8n-Zta}w;&B#YC~KLQ9#uJg`t<(&3$@rNU8qbxpGh}G*7jMC z{4SCOS%+rh(vA>!Htngc!nTuxz3IXSne|AK?5{Qckli^C@%Q~$8@fpZkNxHop^r5M z>Q+(Zz@aRk7=Ug75?-6v&kae$HFa;}qR+m2%9>W~kkWY#V|=d+Da$84vbQ$>^P^8l znhm=pM-T;!F@H1%tuj4CwIK&R=((OJB0LKd{mW%;5%ma7Vl(x=pm9)bwf^FJvQS-m zhWip&|M-;J?@z(cyIdT&FU-mz_d2}p(;+(cbW#R!V903Ju3~PqwLH*_x}8st zGifbP)r?QwM3zMF>Qib*KxMDBqY^2PAIhk3A*<9&7Hr0lMmTrgqrV6`5Dwuc;>Y8MTe;)=8L38VPttxEa2lS zGClNpZU?X1a^9GL?5!M@mLg|0rm_LroS0R{Aml3YWVN8t*ztgIw(gB1XTMK?1}G2g z0}pMeORasJMOAMM@?yaaqN#brJml2eU=@gLTJ}oK78a!EvJW^?@v9-Ja&LV0EX)2P zc?q&lp7g`HO4S<}NhsU`T_H2@nBw^H9IV76?b~JY= zQoDmo?$fiBN|3OE$JpJyy>(OAWk^kU_Oo~Cv%qMrGvz;933sB^X9qY2IA>>-psLoY z_zuYx4EVzD0edV+h8`_8>|tp2K8k*a&SjW3dkZ+J4<(lp*&a*;8?jSlBDmHHOAm>S ztw2H~+mxS5`Yw)4L4XrvX|hcZ-KCw|){L(7A8X_u^VKC7oWPyRpawg_9{&OAe`hh& z-y7>AE)ls$Jg8pp2*bRuWm{)|7Kyo*-VX$!mcsrWQ#EVIb_4^bikMZfj_%2EC~+3B ze6go8HX$?&yRA`B?=0K6OmJ?Dt59oOzf=1bD(?2UImLGG{)V9@ODQOPhR)N)6sGUe zb3gmOY41|S)0wvE)`Os|!xT{UQ0#Uh1E-V1bPjIY-w%JknfjMMijW0u#Oz@%8`lFu zsKO}D1uH*0>BlA^hNXkpz|FcH`FaeKijM&5xld~|{4*@6Uo6PG$j~(HJo0Q892aD@ zsiHzwex3sSAIAIS+=AR~SPq$zLZJ$rx4U1^MO@#*a)HQV)ZQLSvO}tGSDnWRQhXrx zozoU+UR0ZR)X_0|YT1s-Ojm}5hm*Zwjz}z^wSSlQ?*Zzx8`dUcza85EYEerwAc28! zCY@;@TN7Km;pUvpyBpB@W5!WNwk5s?QuXkuoj1V^ASka6P2VkZ@3ONd-6{$1vK&r1 z3L0tTbGrpxY9VqOW_49y&J<){#))3b?7W2Z>$EPWy1O6J1d|qO=xW#T;1)V&|2=u1 zQHpl>+c~`Z4US6d$}Uuz$>BA9CT0=W`rhmJYkY=qQDwB2Bpiy8SI7vHE-E7nrFNyF zhFsvqbv}hDXzq+L3No8RQgk=wCJ5x-;}WPusbldNT3Zwg(ZgOlg^6v>9FWgKPzs?E zqc>PR`G?SXl`J&F)Zi!5`fg{P$LhJOiBsAlFT9J z@7QOak;$Cx`@aIoE}=!09f2Yst|Ls#{@>GLfQuHjVOXEdu~0^KrCMaatUsp>5wcL7 zYxCS?!WfRKZ3O0pe2&fTI5^U3I82Q)Mr~BN`b39JaSX-OOOB4cX%?9MKbjwSUP)?k1Je0pTh&5rTcHG0mYYcsu` zA4SMv9YKnj*eiW0=%3E@o_LJ2#z5+7+~$eQqgVfeLU{x7DHxmm%o-LJQ81Is(m5Ia zF$RGmYC4qTha}37>z@6{b$D5_{ujuT{@?%R&j17473gxXQW@pu=DHsTOvIl1sejZ0 zw7H^z`3=u~L5grVZawEMQ)sBDq}E|&{Wm|iMd}r6p6u4qu^vBp4j$l*yZ6S&2HHp< zB@q^W3IBR)0n!az0zd!B$kpZynl7iJvfqJIAl3>qWD8FKr^%SLtV{?We{WB}sLu=X zTPa}O&HwRyWQS3})58EKp8RWo_n;_7lQDmQ{a;nJunVNx6%;G*%S)-@jh$GFPzqKr zNKjmZnu>}-j}4(nv}|zDZWaA&XgFCSd;a|fI+U!uo&Wk0PCRh?|9kQK^L`=i6I`kN z`v03S&GYk~8;vTUeewS$TB_Vfyyq#juLLl*;Q+=zkG(T=g7O}S(* z%2<;|kNFG6MRDUDfEgPG`Lmo?u`8G_H@>6o?}tS@#)y}4TRP5^Wg1RZ!TF<#89yR} zYrW4IxyAA2GqV>b{^ z(szIBGP~Ih&^R8$gof=Hq!$oAPJZw*Vjc2>jJN&w{n$1;*yYSi_v2Nbye}5at(7MG zE{2VI_6aA}S<*c9c|rF0ZXL?fHSl+64}76qTRpo8am5B<`4rBzGwWOlCR@JJ-GOqF z_#*V;H$NYleP(7wvHRe}npeGevgo|K&ZkCXzW9wY^QI_W z0NfOJ;Qx%i21Aoif#9}KE>=bm;(4=6l`Cf$#At_J1jF_2^%WYyChc#XT)1XU!9kb; ziyhP!5S7*aia7s;>rRUVb;yQU?Gn0NS!{b4W#jH~(%RN|0)d%#HV8SDg+P*7zMR1g z)b*^gvNG_nqp}nYK;3_}wL{)G;hRxaoXpQk;ND5!mH-XT1ZNz7nfl`X80k0j}1`L}a*$PZl zXn%Xj^Aw-qS9X)ltku&EGt)`egu4y5ZQEAuZ8JW&OiTg<%sc*P7m>xeDQ|#8ODO=3IB6suNeq?g(vPl>-ihtOL^GmT*v zbxE8CcsTZ6sKE!jTJk^0iaHH|CiJ;pLPH^gkH|2t6^eG>kEB*&2GSHMN4O=aWBcDf z3Vb|S`SLwP3gbY0*Y^RKM}7+WJvJ8lX|iMJ=<}!_EJsdVgRW~Wdomma89IW>wE$PJ zO^sld-M`oE^e7wg0{>Fz0I>99bA5_${`fw?X<6G4Q0H_Kp!lPkoNIG-I}hdq=H zOB!^y2UX75Hc(zd%ShMuM5TN}it6Ic4W2w%@g7n?2?D~xNyz&k)R6R`55dJ!wEG$F zBFziuQ4fS1zeU@nA)W_7{{ok;OpCTw72}wt!*(cxJJkB3X#<9^U9 zNuY$&try2-GlHftMDe&v`E@aU3k12YeY<3I;=~Cd>M@`u6Q=>G_@+nj81d;F?5g~L zK6+V;;>dtaHz(IK>DJ4I_MICH;tsko8dyLtUZ4v7^`t~T9jX%%Z(ZI? zyRPDoWbt@EPLaMUUW%+XL2|RIlbXv|N6kL zJD=_n>;^ZB(8UnpRYR?HS|_<@hNA82ObU314-Tqq8oyi%rlZwO0Ku15e+`@(Y}Ht& z&Hsq=_mMcApPE#KDayb6<|xK{>P|RH7x3^yc5&j z!5xg9N)+_W2arlF9Y-S%fR)*H?mXVcTu$4S>2;>wIWboY!r}Wbg19DrgoOMbaS0AGJOB3GYy}~m5>r&Rg zy-AKJoD^&2_s(!CV=ZQV@&7NLZZJEw1t2lq`tfVu8!2Lw@w(#tMr#ZJv?gB&vqY^W zf~*4<$R6PIIF%;>C5bA>&%T5JqciSF=$)|h4tNk3rU2ULtBhT!<>TkKQK^CG9cM~X z;7kmkxIjIVhO_aZCv(8z%|(z$Q(l2o=w$8ZyRuE$_RtwtpUy44p|fg&nY;~VHHJzj zkltS1(CPfw;samOkKWK+4F9?X>Ejm|Eo%A-KvTHYL;yEhBo2X{Hw_t}u`Lm2gnG?8 z$OTxBNv0h5>60M?!Awi4{ zh@UjThAVQlaT9g>Z9g7NI^u;+LM6|eM@{MC3Ra0O?p@Rdz~Dw)#7E@h?(*2;VBsB= zAga2}kW%NKjam@gneI3dyJ_n>6PPYS^%A~V71!$0YZBt(7}Ta2E>eSAoAMViUst|J z0bBlh3OCg(L$2qg7dCH;>WSAXylwJbWh^I)>2=`qEKWZUT2qJ(SXBJIV#~QC0rGMh zJhq+(V4e$8D9mW)(h*(-DhE)m4-Om#Geq%7)!S>~<)k+hQ&-y<=&QOFvflw-Oj6A| z7;^B-Q6M&+O4?n|-eHaQ*;(mhq5BTKvY~3m|tpVPk#sC~0gYP&Xac=j# z&3QkA%&hAsWC)~>Me4zCG#Ss!ArW7zSsuSWL1NpsgWLd49q)GeRuDZMSX1J9m9}Y8 zw6Q=@@Um^*P1?^=gQKJ(LEZ(}%L{wn-z8z{TjKSho!wcc>!8(|GOH_Mh-WDjr9lPL!hs zv{n+%l((J4P5*&LViBxFN$UU=l)0AF$9^>LvY=FJ7NB_S#e)oGZFIUGrK+lGkHv6L z-D{5rrg;(zQ?_$+%lG;z#pxWjF@&GAyS*~D8F<$2ROeBku0jO(`1oRMk#&x{h7=G@9;r@&Su* z(JTpg;8^Fzeci7mL6ssc+oJ0rzZ&5uZuQ2id-Z;4B!A28012|~)zzoq0(=7qV3z## zUDQ>;>iCP{We2QWDm@i@&DVQf4uZE;noMr5{etd+L*zy-NBxoz{`av!>Bu&5zueNFG^iv{2`i9 zKPRh~06^Nib+HY%V|~?!D_X~BO3@Ul;8)-o9|_t+w5TS$*}xGjl2jWkL)Q??@w44R z#A&c$P4LFo(&XYyv=3Y;!OxqqblqOiw0T(y4}Bj{l^x| zp<D$Bul~*S_K<6Uu;zA>W?$+;o4j3M394sLdinVu`2z86Jz*e%csB-lpaUV|A zr;i^OO3e4|iLAV%C>^3mi+zH*j&Vt1`*~fD8+?J(xUu+<#P&Zb#KK@>lHErK50fOi*VOnSZ0^BKi z7C5x+2XufG+3bo+h1sx*kxZ~+xH1u|PhXX8;DYuK$BTulGi*}hjll6p)cPxd^dr&C zZL_U4BA0G=Hz^_(DWPJ;I2xWOkqAY_IyFfk^D+zbSAn@2S4WEa!>?XPrEHIpkD4A% zNg24J+9*bgw-_N-8Tb5xTH@jSU(Dr26-mKhfFwHwW=Rh!6P#(SSWg{RNvJ}k62WFA zP*>zq!?2$na?Zg{gx@eGZO#b24E_N}rKY3@Tz47`A}g&1ryW$@hol`}(X3+xtD&f< zSdpk?76tvaeq3XI{H#bUr0?e9GJqL5&A<31Optl8aNQfjGpHVRF`;s54&qr64G5XU zHn4c1%QS9V)x2|F>r?L#ov>;JiKdtho=q+FK}?I^3$&300m{_3^3$1}CqJ6mj-iy@ zl5~x&JM;)yDVZ@{UZH-$hAK**2=;Pz6dFLMO`etfwJHD0wGQvP54dVar8T|X-H+vR z1iyyR_+O^oxX{;^9(rq7v%9WZ$O25q4(m<=sLrowA$_cQkf``s4Sr=_6Sxb)uv7@X z+UY=2=U2mPZ0DNT%JLJ%;IEHhZT%6IoOcrsbA<|61IcdDJ?Z{f_({O;eE$i?!G=9yf_AVnm~a3T%fNqEoN<`1sITAhq{b zqwvR<&woL~t2?)8)=OHuzfcMw_bVgDxTBQn0noatwY6{;Gb(#`8n%n~24j^L+h}q; zCM^Uih1As4l*-`EYuVB?U7mr4f$R~uV8f(A?{Mea!9oCeHxB`wV5#7>$ztL@bR$Bo z`x^IUs-lb61l*@CL8%1ED=no#OdIcN(-H%KT0MZ##avQ}IQ4zRY`n}C)Ul#X zW}V**k-}0+Mx2(=52q_}!_^#QUoK>7oDF%-^!~#8K9rnCBMGi(%ChpsarV?7-m03* z#I^x`oRR3?wd#pOyA0p@eX;}vS(Jz@91BX-(T(&iP~CPXF#hqcUm#Wbll0aI^jV`Q zIhC+sZvZ>>VMWEHe!lvWmF1!8dk2F*yi`cUk~lLUWA1GQk4)TlwC|kNakK9TC-_6A z!0igTKl$^q31o31(*$?5G{BvgErcx&LXu+XOOiK&{{X>V7?w!2_^?U($Jv0X%TJLf zB4dMKQ+5n|0NXmxe4sx>tX_m4#=oD=kK32-s}B~7nGf_~(G^^t0C;R!?_SQ&caw-n zOVt_eZiEkr?1Z{ns5p`1^}-3}ZAI)NYk_usw*1RJOOZU85U7F!NEHFPq0K$>`4Ld; z@^9fG;+wt$G#kkUWnr=k+-JpGIusVy-6x9 zD4j5DAJL<{fpP>Q=RCej^CBMSgbwhI*OF=omlr|{&(#x@3p6GO!#d?@Q&^o(@}d20 z!Lv}(qNHf#G#WWwznpe<&y_H?R5jHK zMVHQn>_8_8EAO=Hjq+VP-nm76rT^$=Gv(TqSg-mG>~VGtoyQtLw*xJ4HnS;WU z9s9OxNq$3)p~aftrmG8D72WIA(g0jc;IaAk;Yx$7^u#eRG2;gy`v1=MQq=>mPLPJ8 z@87@Aizbu}E2;r>*T}Z$Jf1$86KzvG;ZV6S+9{UzR7@bE4O?OMueG04L4i4&MfFng z$dRGfGw9|QG7UIv$#YXk7LE$V7*ThoalC3MJXx39J!PI4{OmT_W%vHsWeDF?oWCq8 ziD$YPdjY!8Ji^>@ozph87ttGN_us8YvJ}Tc;QEf}66~t-1)AWb2?S8D zw9?~^P8a3p_g^wbmVIKO|9x&&Pacvh+b7CAMr^}@;|lLE>zsPTHpmMyh%afxP$rsJ zD2n~M#XqxT6oinQ8OO}OS^RXa4@$r;NjW7;^ANBjFRu`neF_TqyhoN+z$3YM>#rwU zAQrzyDf7m!CLjbl*|icSwz<^>fa0b|XBMhulvs>=BP$Vnwea{bFw0b?7mJKP09J|M z-LgJfDBa!LK`#xy;%N)j{M=RUytPPe#Z^MiNo)F$F<>DhSBV@%#Lv3aq#iHpUoFZ5 zZC@&6Ch|lqJ5_f=7TO>%+`015CwOB-GPhg|d9B4mf)C$bZI`*_1p&l9HY76u0@d&Lq&u5~`*-@0sukS<^CPVTS zYr4MEn>_$OmqW|x)Y?o)${6;6+jGWZM8eyS^+w}@%*W_Nl9Mm$_ks4&$wjutmOq`n zXD+MToV{=2zgoL2oSJFS)EjFS+sA(p(uUpLIUhgP;zB+h4dO@1otp9fo-n0g>1C-I zux_>+0X+md^;KOU;QqsHp$GuZUr4Be3<+JwMIDpoV%PQWIF94Jk^!gM-&zV7=feLV zE1ljZ-Fsx z@(GrH7_TK$1%#!XC5{%wt>En69PUH%m2TYo45Zae?bb|5PZhiBdp=(B40(T(~mAsEBciX#3b?(YpiYDJC1wCQ|B4mHFVT{%b1)@wWC|Ddy18!*b> zvf+DHTtWMKP9YTb%Ah(6N~)k?9||f3uK>cC=ys0s{=nG^FX!;vtM-6Z*YIA~;(Ocj zmj-$v+nnVP(x#0dFhdP~C(O`Vlh4nkOjo8aH7_0D!P;*IiDdtpA!cV9y5V3iQMBNb zoj{$#U;sI?J=~!`2u!*~*-4*5G#OqSR7CmlOHyBrA~#q$fZhA@;VPl`Q&vltDdDE!*(KLr`Md+#l^!nw(SREbkU1F~LeI=Iq{@=4NPvV|y;xg}#K%NL?w zch@uI85WsQc2ECtw3otT?706?fvUr%XS3mQOxc(RVWFP)=AYl-2j|R4yR3kU7dT+Mp0y#%gikup&@i69-sfx9F*6E4IW zWpMV1mS}%bLvcgD?U`$O6cEHco{9D(e_-OF?tm&<}x< z&6!kPR4`0$I%(0ZmQ@ACGMpHcOC%4!hq%R^8&5zUW!G-57c97Qh=|C0R1N8>%?qV2 z!|A&YUnL~4Zkgqc=;WrmS#p_|&H;%U?OMBXQTDcWVS-fY*-y&3Td0p)t~iKQly>t1Tv6L0xCeh$lSb*3qxg;K-xr zpS4A%4-$3fD;m&WN8k7A?dYWfM3$%E)z0&uL?E=XuHlzI-3gSVGvzum%R8^{0_yP1 z1~L2_fy-6T*7 z?L!qjl;G9n5f5~RPQrGM*B$t39>?s=i6}J!+`$)vVnRaKk$j6g_39)SqBO(`k9{_p zYHd5}`(lbzyx^lT@u{y{y_(%sDJChxgN*jk!-xHnGXs*<_27)hv!HgBHkBkJ=>5*br<8uLa!~uhR z0>i5pU!>yV;{le}cJn|Uv*!P>_vZ0b@9q02iAs`+N}&}=60#_nqS+Kh+mKm?%9JTn zhSfw;nI)uTXh5YxgoH9Hio`;uuw<4Y!?`|cSI>U-U+4Eauh)5<^L+n#_O~_otoL}| z*L_{r{UF)cvxIrQX7Ijl1RDBtjgf)7|jc4k<;=;o$YH z>${A2Jl8xlGDod|xF&CXPk8e-w?GN>c!p+!b*(FknpM|v`W@btSAuyu1xnW3@kufj z`yWN>|A4pEG<&SSvMpv))y%b}GQ}b-%XY2Y_i}Tb24kUt{-LM0{Py+uf9h#F8WHPU zlx0QbxZHa58L!qo=1iY`huQZv?qXvPNXDcESqr@A=PXmgacHDtCU z5X~50*i#i~aDd>oy$z(?N&^Q;h|B$Auk=ZL>^zF8VIaThe10o#RyW6xlQ1LQ1zPly z+4tu9?5jj^5ya(PkeAYF?HFOHcYcq5SqRSDW(YqXy}E7rzeoCiVwA$m6zHx$N~ISw zpKc~dk8D4uPOo+wDKUAr0VfXIJWOycoE0X0ZL+_nhvYnlJJ{`qoR8wReLKHGZJ}oc z@m|&MbMp*m#VK%%DNAk2urtED z9$f$Sfp`~U#UVSC($f05;Zt3^gnlRqnyCisCs&+>9(5#V&vAc2-E^yk)TMq9ubJb~ zn$4<+)~DAm4YAlT5Aoc}1^ zVL;&Vy@l*Jpdg0EU7DBHcd?ocld$lzaV+-+0w^-bChNb zZToxhNH%5HqYPt5WxM4Q8WvV!FNT^f?c%NFzn@D=(D6rJOA(~H6SKewNr~?j8 z#U`dyHnXy!VH}vXQ3HpAP_iDy`uB+LcBxhpC`lcKsS19; zCMSn@eW!Q(YEu-ne*eAC!7=wSPSE^5wOz=z#G&}qi@j%^U5M?CHA30~OXg6ylSq4> z;bnf5uWaAn4Z={m{T_ouvWO_tWR~#Ae#~00P>2}s@YNWCXI8r;-$Lit{H8bUTEM;G zdo|JyYs^aU2+yn9l$U?LK?5QO*^72BYfm6?fDHwHjsG8?{|Lwi6s)|qt1{tXVY(TN zezJnagv8vIvDBP8N3EW3M*3))HrtC{A+;%V{)HeZqd~hVl{xhH$UR~N&w^iuV2EJh z-nv_CvJE_bnifg?_spBiA^T4ILNuhs==u{#lw4n`=G_2~xg`c(Gk_)Ztgsb_w+QVb zU6In&huM8uWmz1>FMm%_j#cXO*KK=Fk|GFd%hj}3X1|`Y7;VmT%zOb}hdJ-@;RSK= z+3eWtOsum|VCnBKxB?Fr&2QnTgdN5Fc_Bu>XPA@qAMbgjOE@3ADVk8=DOrX_y{Bke z#w&i$jeqyUmsn|-e!n1STR!o*ZrS=ehgiL@uzHz~(+vTE*1@aXQX@_7G+~-n%k1j0 zT4J*?;7lfY6z9#1iqf>`?45vCy6Q7)DE?kMoYSZ<^0;iEQ*~?f%MAQIRpgT&ADIAX zOV*<=Jc^YGhJZJ|+57j>tlnnZ__2-m%uB+|S8DlU-``8F2ov*Ftal#sIj#VpmDikw z28@3HAoetERkT^j;-H%$sEIt0W+sn*?Xmf2(lm>H&rfX`eP*B8x9t~vj~YORE%pn3 zkv|TZXyk9MXIfdt2`eap;JC&M}dymY=dX{`gcN)fn1etnouZ zAZV1{Mu>Nk8aSTz_fQ00uc3tDajb80-G{!~-&v^j_YN?%g+~+*tb7>})!hdr^FLn& zRAGzQ@filO0zIOG4w#;J^J`6-s(qsnTuMwp8t;N$To=iD%QSz@&vM7KrKlsmCSI7lZt_}2k`PbE{Kv-c_7Sg| znUMyc;#>@sGXXcb_R73K4k=>+^_$jI|BsKm;)v^#Ob-0mgSzV}^+&d>KGragG(`O^ z!**Y<4xR}cXc?!Xby!%~bE+{iq}mGlz!anfjeHs9GQV#4OHbx@I0a=*Y(j;O;-GA} zKhd-bFaO#Ph0(nX@GyIf*(m*7Tp|DSkn+=KGR?{Nsc?mNPRh0A?0KMz5qLuu$Dpaf zQT%!0Iw$Fyk&4fu$ct{~8}gD>7USP{v%O;}%;HdB%5n^*kmT>4ceAKfCw{UlWGgyO zUp6r8^1>H=2W;`kc3;59UjZ81N~%pR`s-|^ zB@uH7d)A*%7i$(l7`o$Eje+Acn4+Lto88Cy? z$%q^O9WVd{-<0RS9?bhlk?eo{{8_U%KYqS{^nZ<-fK1bg zq!sA)i z5?GI~_Amu&%9s;mU+et)=vv|l!c+ow%G5BJ)UngR@;E9ufL^JB&qmG=dDXLKLyiy3r2$Em2KR6;mYOWKJzV&h2R(2IPI0H?G76JBiO{1|JzTN<$F z0O$}siFaXPzp|!pirZ|5#+nr z78gUa8JJzQCgs?Vy)`Ehp_MAar|x;UyF+|&TO2&0q0HpadP$&X1hmk`nw)kQ6D=@Y zYj8v_%1yNpHRPpRROym&G-U_Fb3~8MM?Y;`N&uA;l>S#+46=@Fv?#xRyDU2B(Zmvi z)g$td{A~m$nDh3h)%!j>&+(Co{ZRcL)aA*fgWa)s##$%~T7n7VIyG1xdjgumfKV-> zY+fiZIh2dN$?SmLoR?h<3t_VYKilpoCj`Ky$V0v)NeJ>Y*bjp=r|p&r0j_)?1?`Mv z3|n_E%Q)(miOTze2>S<t6P7{b=Gl5!JMG@54nwQUp4bF0h%n6(}5{ zn!T4EwckEKoQ|o)HqoA$Rv?}aSwTzi4GJ0oiuC1mB03nG$61W-C$#W&*jpJWSQW6! z6c_G{0&PpFl%}o)pc&Af=OLu>CalDsM_fzX#zJ_niT3Oz#6Jk&lczbowiW~ zyQ6MM@|4LtrVz?Y|6VWT2x+$a-j$lD6Zia?^$aC~4~IDYR5RCA2@4C4mQIM2Z*Q>X zvl?LFRD_Y!*~PF4?M0lbo_94)V-8`~XgZsWb=*861OljTpE^cuNp365!XMOtOBm`) z7;aB1Fb#pjRjiWv1??Ya-c9y@D^@TjB9UcT-fHcCj)H_UGSULc1kT-zoW=ADxJWAy zM1)Pw&xZBAS6lj<>Cwy(?smu;BHQFmtBrTu%?1bE+V& z>PK)wt}eR;KLigaktNl2>ztW82pRda#0^%*e%wS$={vYf0l z@CrRymzra~R(^IQCYbWF6vq|s5gtB)2m>+f>!I^FugJE;)YACW+X}exjbq)>anY*46cL0wqblX6kF)ov_nT5IM}__~w2T zvGV->zL)3if!YLa7I$%Yhy3%-ym&+6gafi)-Hf;$|GYDe@8U!zT=s1D+5g72e#8MU z-(vY1p#+EfMc|)-h4ta}j)nh-4(90{DdrOUM>O#=y!SlLTf~CP$p7*Z4ij9M|N0U^ z7X7!Ev|vDY4HqFE>o-W^+RNNH&-1r|iHzj4A_f!yX|ycE6D6KUzczH|l$D}od2f5t&u zUBGIDG^99-qv-WN0?B!f*g1x%`QXB}{%2IPbqpEaA%Q*r3`QsfoAK~}|NE}>x703H z{$twC?pBCliTUS`yx=3vDg865xOALp9y@?b_IcM>Hdxmt;Od|wY!qJYV>-M05JFQV zwa9|@6=gleDfguY-y6di{&1?>eezlVR}NrBgi4@3{ODVuoyNa~O* z9*S@8nt`kdb1D1hXUJ@~6ieQDV#1DQ#JT?CSK-@G5v{_K9{iQ1|9EoVXV7_YJC=+6 z+g}pN?oC5&3jyzceW5$@9YjmERR30!-}xdjO#4ov6B$>_`ag2u;nlqK`+5L4wbLyP z`Xi%y!?tLX22RY@fB9zwRA2u4pA8*+W^sw&VVD17SYEW#86nET>OcR-Ux1$ryQtL5 zyot`W*s{MdMa%`@lpU%I3+d7b(|K-~rLO#*xRCDm(K7@EE6Zs#;OYt8QFi5oL zJq`BgzdZ%mVMfTDF{2xP&ZsfyZt{Gu&DK4#o#&(PhU0$6>w+K45sUnP|M&lv5m2z$ zd59CulPoeyUYq!Ge?uLy7CC+6;fFpu0{Ny<>;x!UzWQ1s-QFwC?{*gkQp`%)&aiBv zdoM&{?Q%R;d3q}&$szgjN?w@FtE7b?Q!}PAlltyzD{#32`mm6>K95bRcHiP8uT*eSp*!=q>FoPvBGvDk|&e{z`UkbjWYW&;M8vV{SKti zZ)`Qi(w83Ev4e-QV*ub!#ji22Kvt-AZgKsW-{@cR+O6xhFA&WZZ(@}H z;~V09sfn@(OoOjHf!QeV;Bg~jpk>K{u1~mC>HWB9aTmHwG6bs-l(EWB0i&fGm;d`6 z;yefG{nilg2%=hma*GYVH_beEX3}czZBCAJzZuqGNAa7j7r>AI4SusbzFd{?nnYDz zCu82rja{8TAIepNk#rJM8+YJz6wDrRDz_9{xXsi=q} znD5#t33^69h7~`?@7G^LBd3pBp%aHbhA_2BYv6JyUXNnA->@N=`*&LQ)GtJ4t96C` z&`sBsn@G0AFBf04kKS)He%JB4#;b_+ldKnE2U$Sui$R<8dJE+1LyzL)WPne35u$#obLa<`D)ftFF-Po#!j?^KD))=ijEtM;(`hAX^l92oM@mOsN!=pvN-qfwLNMUg9O&~06sFbOKmO`B80F0U* z1123~{-qmC|Th%)fU8ZRlSMTVK4>{|r4t8_W!6*yrCc2Ke zD25+qrz>r&tLGVdF^WU?@h9tdPxJLtbOq&AO6o3OksGr&ey<&AEc!Z)t-mYRG#p*c8#FX+w~- zn>IvuzVG_6tAhQCu@WbOooRvEpINWcvCIAOMuNT@Fik}}q!UyLy4!?J)a{tYSIS*& zd~`(>>4b6JVG}(uA7#P2Gpq_%qv3W0Nct?*fj{?Z6KcFx~_c(cl6#O|(My7nW;&Cec~1U=G(%DcL_>K4B7 z(XS!8m9|m!dW(COrkYeymK2>s0-KtZiI82}M!KT>-w!9;BEl#rEd0!Nu@7{@FBwJ^ zjWSQ&cGffIn`PKU7i6KAjG*uCBh1Ch>(G$*KE=uP#CD-iV=!M12za$AKAitKH39QX zwC__^Ki>IP=!;9<_n1*82IdPNOpZ_I((ethd5j8w+^cj`_J!FROA7r)DTY#D0UUE) zeKgOGZrQP4e~odsGuI_zYiTCA>=11jG zR`|pj|M@Iv>=wv(I9VLeYUer7Y1cCU)~1htFS-4cw^wirwJWmI2-9i3buT8??x5eq z{2veczegaZ>wly0zft&m>;8XvEdFg5qJJZ6#x9IZfm1hYv-e`wXV1k}&7>z|dFa@J`H0+41ra9|Vh*f%Id zvu?pRD!6ub>kbnhxmJ3(ETTekJ=;xCPD=0m%WMgV8`Rq5U1&_*3$9?4L2rDBnsU7s zimzWRVn^Ysk^|vp>N6C~CbiPjUvj*9G>9~4&n>;fSzMOz7md<}K`b!0QYa&)9t zDzX}WRjfeJ6Yd`(etXD45Z^rQEqHeG=9~L#H4wci7JB*dG6&RX}+#XqZ1Hd~&NpdvS`j z4Mpg@2_v0Z32`+a@wXs>2E$SrDn&qWuRFXaI#vNmH`~C+D4BEoT^x|pBvHbcK-lob zM>!S?l3=@R4-9;avQOJg#)8KaTkSB4RZ;rgVX08D0)pw)(T+X$lC%bLb5SxGiA0eE ztZ*ea^<72QLO(7r4W0@G4U1YZfy@(Gc+Vcl0WQZaX{$desTuEd2CBY%DGoD|pr)qS$jT&e!bHrac|(|xbrTC#innvn5F@Wt?4q4>gW#l6nN0SYRlI+ws3G0> z&$Y!b#}E{9I&v6$U^2>U)y8q7#srmBb~XL4iZ|`q2)Qzs=)~=+Jxk@-&y*sdx=oXU zJH@$S^WMO;Vb_xWSBei~?CU;R#(IvJa#(^sFqs6I`}Q41YKx{y%}9N%!!0f*X03=A z?P*=zuNWb61)!guho<&tG{r3 zOt&X}5!oEM-R6cYc=K)p*;`SmS(5q{yzGcba_Y$P*nqM;a&@D>jea|^ha)ImkGCRj z4V{o~0(XCUy3o52;)E}!k4fdfHAl|H)|i7?`W_(q4&iLZE`o6mw&a?IuY?2`g7(OK+%2`;c?L?`)zPykt~4w)BLUco*dFgKmxPwU zoU@i4s{1>MauSR<$d7ScWp5kn`B2t8B2m8d%&Pr{o5sT-G)v0wCrDePo5#20^lsQ~ zeQn-Sy3GZDZwdn1L)CE$wL?wj>xQKSrEmHHdbG4U$_<8xaE+})A;Psp^A`9^r6X|l zilcR7GDOgHk2!KRHh1if!vvoxku9I5@WPCVS75hoC(1qM?l`qZSD>at`>WMG{YjZf zcIHK4y>!)B4G37IRt%st(mrDB`3kn2L>pUO)f??e<|NdKYQ>r5M4g96HCEaba9Tz$ ztMpci{-_l&@Ag^>OT6q2O8LP_JTlq_@i~IaBQ-%o;wx0cw?E+Rg`D=fdfVq6D>JN0 zPUJpe&<%0adMj;&+HL+!Wz@poR=p{*b#YzH|cNM zp^ACbMUd=#^a-or&a5e@h;9upmFeATu#-R76ZIx%`W*izbqi8;JPLEZPaj{_WT&aN zlLN6hnpLtd?s6-!OYN2+ge|d|FLosgs6}t8ncT*f^GQ=p+-wqV1Ik8KFx;Zj(^xrO zYS$+TO-_`>&Q5(n%i-e@DV7@vK73xc?EpHVgt@%1#LAul+~70`f?^$?cHXs`XI9!V zdGKK>p-q;s>}3cHc*rZjBQm>)aF5?Y2!*Yf;smztzR}L#cDcowWJqQRdcrNG67(%I z3?>>4>SiRvAy&JiBBf;!%v!&r|9A~J*nsafJbx_q?kfLmlzkgVm+rpEV3^2Kcx5jt zR;wCU5VqJ$QI6Y8bviYJ#1CAYPD^Mubl&D|&WW$Zu-JM5?;p7xO*db@?Nrjb`sNiM zR1DLif+^)ulIlsLHd!X{T{CdXeIb!I|1smQWAbLe*xnDf_Q0cGDswSdbfqe1dLPu? zelA*9w(NeMMF+pHajDA1)hKQr>~MU|mi_E@lHvZHY* zwQzuJP9i9hnk#G19jRI&@oi+q`g1oQL;G0gZZ0c^QeSHH;)JR?nhDX%r$XVZQQm0q zs#xN@;&om13@77}waJ`*QKCtXBHEXj8}5*DX!JhJL>3gNEZFZwLcL&+fzvNSR#+P@ z+vg$#8SITNQK3|*c43(=gdwg_9!Q0WDZUF1ACrFbRU-65>ryrd4;pUQQb>=UeR zqlK-OK9IL@JNj>kx^XB^W*pzf@GhzB>FY28;eMT%Xh|ZDkBOa^BgRix!Jjg8Q2uUw zd|{5$>;9Wv5vOau(4Hl0n7|&d+dp<()e>HdqvGZy_cV6>DtH`qn4|Y{hV4P7G{%Rl zbh>jWL0GUD!@I>BrVfe+;yC^!Ok!Yu_zL=Dm1?8PhLI#1+$-h5<&f88id#~Xw|Uwt zC$?B2{(^08nZmaw4?EGVBe?7L(qfB@*NgQUPD&4)myQSCoaj#0%x2addRSd zY2yKI=TKl@O%E6p!U+}25QcLILj`^jU3EJ%5wzv2ZmN*S{j_9ksw*vJH2{oxoQiH_ z3sPT{t@|og$yqogeDEbJ2e0swG_v^C^=^;+taG!*yPh#bt>42+6h>~$K6m`mb7e81 zc8qx_DfD)o5wU4CEY6AEcF}bz;F{(*EGo5m1T=%vG0zd6M>{zcYkyqo<0W6Yrrb8V zJkiWhaN|@QNX)ISbLssk)~3=W*Km%phDyI}n*Ejf&8ke6y>`2KzlZ}`>d3h;!eR#d z9>W$HCwPh7jL6hcS?Z=uKf?Bn0Y}`5OCS?(Y$NC{LayIKA!~ChiF$LA$pJgLI~HN2 zifANXSOf*;b$Lrt_3g%#nU z@hqntoVfkAcY`7D!KlDKLt^i@Kh9-Nzwb*H%Ij*RLUaeRZAszmRMqTwiCsjoq8Uz& zNvm{1npoZpU&WlgJaJ=gwH~Yef#SQBWUriW-rM$6W1{52q4=TbQ?C{o4q0s@ZeZ6- zdh0URS*_k`>?6|V_2{)+nK>zSiWPEZQ9HsJ-;*4eyzg=4UNMGxX>_zRPoD2-D%8=R#ZOd1A&7I%;IxONF*}x;wsOjC;JCXu}!OgqA zg>d?zEtK3<*&#*IQwug2+-_RXq+&txo~9W&Gn8i63iN#EXIRwnf&K?{7OxR+wR2kw zqLNzmeIG!x>-1_c$L_5DTB?-0Wjl1n6WSJ)u*nc8EiE5kJ{ZdlqsK#! zMR<5PjK1_L+n36X92y&DMikOr|K!WE16=EC(r!Yzsq=+Uet{kkWS9-vdfz+;-3EZ9 z-CC~53#`^o73P#7j@p>CBt$?x{D~j1ZW^pe43SCdkrcHYaQ#>`Zt3$p;n8@;Gs@k4 zJN^Ljt`Et&n)?m=B*hL3rgPj;=-N+W5UhfZ_@>uXsg9CGmi?6@*Fb75KJ@C!xkAiv z9a=kr(Wba-q1OYoldo78Y4n|qEl@THrdKOn9Frx;*_LT^Q-e@8zUSi9pD({Nod4Vy z+2LT=7v;kzn_fKMzYaN_lce<9qDDLQh4uW6YauEA0M&&+P6KYI_>7>DkPjZ>QA^(? ziytmmcn_7u!&RqCj~f(7A2?ly2$_F;0F2hR-59%)d%Kazuu8QD`g*BX{Iu)<&#J!6_-bKz!%-Z~}&f)2Ioh5Kt$ z8uaXP5*$Ucy5eATxu7m`(9*Vj{41>8qBY^aa8NCEq)so?f&{TV4bnT1{YnI4duKNE zccIksKDIP$8)3UAZB!a_WWC@yBontho}fYDfm3=V-oEc2p!=f9=HH3v9DqHSxv-HA z5P5JEg*_9aif(|^ERLw#*m2HLJO0RA|M`Jph22o8WI*k=&om^Mvg5+mWICTMztH;s zfKC;=Dy3=3@JFe*Dc6v-J}Luhbt3HW=9B4UHqoK~c@Yx$|BnEBesK`MVJN*acDfEr zo|<=v{TJB(V}Z~+Z18u6Kx`moY17n_XgYSr2GhR^Ig8O<2+cx$L1LSM9y8rmMJ;~T zOF!Xe_BM6jML&S$K+62E@NmLN^&}Mr9Vrb%&9Uco(5Q;g{SYH@lS14-O)m(aWbQYt z>HGhVPd6XsEQUSvCYu>p>WzK|yC?5!dP8Y6{9y(`7InB>qBL&jH5?WC^+o;qJdyAj z&EwLuATy;}TbUb^LDnnXDMW?FNzS%0b7Z3WKI{T4@@}F{^7C)SrwQ4Qkl_q!Tdbb5 zp<}_-o%k)RYquw-(SjU{QtH!hPvy18{y;riLnx31Y)uF)2@>MlnDLV65S*qkuxh*b zX=#V!+EZ~tTFHvuwQviOZ1{xZz5CVV<&R-QL}mADlf!x2X>L|?8<1ohwNf`+B<`6Q zN-suC@XaUK$qY9Kp!v0s%i2fKw&br%uMEC9M2It4yoCe>gSydQN_W)*cwWk$0VXl>84hP1CgAi689uiS1d)}|k^m{By%&=M zfnc2^2TZfy7wf_63}Z%QpSJxAsXgyt{UQ8VgsX2TQlD zRgx-*czmw>48q6h!oPSqL4{<*%x;|Rx#tI#odGW495bdggeNUuqK4iIZy6?1n>$Py zJ^{+@m(o;UN5EmP9s?U${X7Ee_UO~&0L%IWhej|x-R{+EWl#5hMBx*Mt(9PGr1Aqi z;l^P&rKUKVT_9A{dezFq$Qaln?us^GfdcY#(<%Ig^0{~|`J<)uKT zd1FmSGqiP(MrDr;VIgYW(dYcv1>EOF9E?O_y*S&C)$d$ zOP|q;Fuda%0p6o_LPuFROxvCoGy!|p0>b*j>RT|U;-paGkucD{&tU20*9C`*f-L)q zZOZ|%WyreTA?u3D8Y&e!CvI*T9(hgf+jWmk-_xDC1iwETF&Yw(qKkm(QPZTk7f0A)GF20)r`vHk{~V1*WW~ zmQY74gh$Rs3zbV0G+5hP8m2IsW*52zmJSKHaY$7ub@!QHeQ~JtuxJ^jAqKwZ4(*LyOW2jyk{Iw$u-z!+W@{gE2N$m;`3c3 zV51@$G1)I(2W1l3s8aex;i{m ztFddppCc0)UQyH~rQaL1Rs;}ft``gwz!PmrtkFi|6tt#`|Dl{747dmUXy_GRj@I;6 z1FJ)mXim^!o_iP<@s)Ayon{3mPCva8+~l#y8J@BLT2L+NugThMMHwz%appiiOFQ7Cpl%{UPv8es?DUX-wv_XhN0{+GhyLS0 zMziAK5O=dOVl%rwLEC@OGMivr&%?+=cjV&S+F8EA;E~fw_i&+p#mPx#ts#&LjT}n& zyPNX@w-L#f1G!&h&orjDjen=w==KPTE9K$Gb?#laC!3EpxtI_sWd;9Kq3^P^a@Z9( z^Mk@0Us-oe(>d!bksgY&S{-skQZZQ~zEZA%pg+jUw)*i+Jq6x6g8rMW0_w)?FZj); z1v&lJDm}Al(E4J<)ViNbS|Y^7zz}{Lo~!nE(m1w|A7dGJt8$<0KDhgZDyLsww~L9B zOmXuPoii+8= z?O@)PHnO_l#We;@=H&`bHfTK-v55PxZdIs0l64ce#lD|#per>!>NgV1!QE@Uonf#H z^loAyt$bTm3SiX6U>pUF>ItY|m!!tGvg|$Z*U<(v{3NA(C{51y6G=AmEzb-PvnH;ER`+VQV_{jvjINZ6V69H;8OD+ff>~K}MWT~G~I+RG*@zgjZem?p@I2!jW z;Xuons}SQ5X@CCX-z#MES(bJp$r_7`xe;Ah8fdautB;=?2*k7WyrKSP0RiwOFVCEK z!s*8%A)y^)YoMoL$W;B@(K1q$VS(q}#d#nz2re$$lk?6B9Q7ENrf#0nwGkooIRUae z&V00g!#!HK6Isbk_mVT5>Iup6&~6{{V{;AMEX*9Fil*%KM<^9u>pSypvWf+&m9&|z=n z)$%KQ&EkLnk_S;`>zXR|JYg$DWO@<|LDXtbQZTgVslFekG_T1-24?iG9G-V+@2O4% z@zerP-PJR2pW5a|i*c>fc>~V0GPD0f8(psb$rdAQEK!LSr-_+v84t zKH)G=%I1@VTsu`YMSG3dzRO<^2R_cG_Zj-Q@`0iysqd(j%f$KE%xH4kbRm(CRtS~0 z@sruSYpxv{Wq;M6&qRih1o>FjtY(gX+F6gdbo9{_P9Ecy>$!WUdh7~eZSQq~)31!P z5cxWqRa8ZCcQQFJwExu(a$<3&{P8vSq%KYN4CdI0D8_| zSKoWt@?FvZ1W z1{dfzhfc{He|sxb8$NvrS5yZfe*f##&|8?i8LJTI#J- ziggat-;zx)+MLB%jGg^#TF~X0G?-jDPoKEt41YvKETr>10&0;X`37HGB0?x#mh1BM z6OxmAVai;scYRWKN+jUvfj8ZKJgYcYJs{1sg`w_|Dv79JsaUsii%v^t1|n(1i(VJ< z7Pno9prCsg<|yd%eZ4K$Q6sTx8*LKgY)*?XU}{ZWxe|_W^1=-Fjy~IrAeErAv54OM1Ybacq(=MJX`51YsJ2^YeTl6<1O?xE3u7LP4Iiguf4K3_*R)01M~k z@)vsu`_)dvO|Isbx$L1cczkn+unEN!gkJ)dDV)HWrZcJJw^CKqt&J?{jf<&vQI1?L z*zdvb2|?Xn+b<<||E{_tXW8rho#e@xbC=u^P7)j&FD(Y3;;vx;d!}z+8?xn}vlJTa zpTXr=qhdyyEO`a}u~TlRFk%ixR5#57m!C0^S~iI|BIo6YI@FcNg7Z8yb}_Zu&L$WM zxM4Goel1hnkoocO0q%}3TNnt$%XtQ@#utUtN)p@-caGEt7#>A+il-^DjpVXFY26~Z z$*w!nMs^-u0-^)O@Hu_KBz9Tg{2JxbuEC;ZpTWz>&TQ) zMmHM5xE{)LdB~yeyWRGJbgEK`LSw&U_h2esDAE05b-QdQ!@J4TNW`-E;RJqAbf732 z#y=Q%WScf$`YJXtmg3h>=4a_mpr+ZG8V5!K?OcE5wBi9SaHen`4zAFX>9~4lQs#Zy z1NG<~V&hjOnjRiuBGlL|d!}C<-OlMJ5}RgLT1ut1jeaxNwIB^yjPBv=sI1V)txvMs z>Z<;JD0lJ;|HJE}Ap*OPUM5tIIFWi(0PEdliWpwJ*UxL z=f%srg(_x(L=&2U3ryZP6?CpbC2 z#Sb|}K1>N-u_*H4ItDk2S7Y;ti^<4j^+&$l}XuI3h9@-%AniP=S6SORCQLQdqU+*j+zU?CKH8jx!~3GDLi1Y&0^ zv~LD}1`x;9MR@%G`B;>9Iyhfn?0UH7_dtES{x z>r;`ZXhx{TR@SkYRYpsBe0>)2BKrH5*Xn09wun-1?^z&~5-gB)MQ|7<-9r8R(|IlE zVSl1N%^caKnF>?$<>;Xj9iTd$l}JUa8RW8@T1$GKm z)C2XTXYfc1|Fr3Ydbl@K9%hMKZb_OBt+-bN;P|$De^e{M`bnCfcZs<2i%ptf!Z&@} z=H6Bap&#XLb6H;s7%3a-(9$VfNNURYfOwOJ6S9c@ws3%qpucgoD3qlz{(E4si1(84 zw>$ihh1ud7+do!KQ=0t%?JUd_7mQ_~6ke7qOnuP%bZ7w1wBg*<>b(v5dXvQk(8q{+ zR#eFj2Slq$*f#1+Dj!@vRY+MW+umWOV5dizxwV|hIW6=tmZ?OkQb{0Y1LGIi6a}7e zi@W))_xN2U zna{{S?M2%7qQdiD-tixR==z;tsag`{wn_zN%~JIQ((*rG(~qWRB)1=U3vP-zG#B8k z1dM2?*U2W-l}FV61~5Ud)w71RJ+XkDg=W61C}cD`Ty_>3%K!UF`bm~O-&L?wzW3do zH^{Y&scc7%{_zd}FJSpaZG+E4{a;>?BGWDw#{2+9f!m@GCzo$%jG*5DfWT}1j)zF5 z${dG>_B4G0@rWy093F;|Qr$$4<=*1rk)Q)S-HD5(7@ot3Kf^UPRKU>n^M!mVpjYQI_Hh=YiGe1` z_o74_g!xZwi?l9bsoOA-QH*x0L-(1WC|0WqIFxpVryQ(Y3H*;kOMLeRyDt!QKo)2F z2PigVDHLHY=<=h)=q0u`uioUu>U( zpQ5ch^nTs@UaPa;MM7y|?LA=P&cth_2hT<~QSNqg#Cf_ZcDKueE>QR2zYhm537a{p z@vuF{!g~KHs~sKta?|qbl66CNHgoK`#!|Rjl^i%i{SH22kc%*5p{M|1cJ1u;Aec|6 zE%s?8>bn{zt5x1wC{2{Q-Vf1GA_tFg$Xbi<+!qd9;_&2@^P+qy=s*k&xqlK7hh9z_ zWx$Aw2a*_CK6eXNxvIDSO|QEImbxfCIvjv(Lq#)cXHK7i7Nc~0MAVN1%tjYrR8&)f zTp)59X?bQORC32AFE^oe*HBXPRHvk^80Ufs(9ia7B)Z>bD2(+{9iLPLQhu(@C`vDa z?dqA4!ExZ0sk6`fT0S8N8~waOUG}pDLQn082yt(h;>$36?>ZAXQ)V<1Y_I*U2#!-4 z&rbd&ANhI*>P*!|Osrg87PSwwtFH8o)myHUoV|PJYOoZr<=Ch;0VeKzj;z@`L*Mkk zABaafhuj#XDE9&WBVhJXRdrv38{^A;`g)W+G9?3@vKzxNN_ehaM|Z#g4OFDP;Yw`V ziI8C387c~HnetSq=cP57f~$|j)F2_}!d`jnp5^f~9XVxdBI3gCwIiiK3o9V=}}IJrYXY|?tO6rD%_Ytj~C#pAyx(QN&bZn_{zjx_sSi9~GO0i~qMgFIRheXAH;?lB6 zmge{i`C8pfs=BB`Wkf{6n_x+0L~gapnHCZ6>e+?UPI?hRaXs7lI2C6&JeeHO;IF5z zM<7){xEpt?dLrWZV_##;$B5QRjrltu(2LAPJ;FTq=Az>D-3v@ZaI=ea#IefJy8;a} z&%G>Zp37x5hk};fA349*|5|x7xWH%E>LvuJv1d17r^`)r*`!?WwE~D5j|R zC>ssvZfVqqwxa}XwfZ{hr@In;Vbh_m3qiT+7`PWJWj>!@p-)|G7?@ZUCQz!9t+_?6 ze5rKTE#b^i{y$lV?F1!39bZ}8&~{D? zFn!VfM(zfs>x|q!^z)p#v$Vs^aF(5`Z6POne7}b~b9*HlLGD1x%4;c_KlWD>N9V$y z_Y#V0giVZRZur@xo9?CRK+(CbOQ#&;%<;Id3WqTM%%eHm@0^X<+ex76(!xa>%*EWs z(Y3)!(F0|5S~*d`)9x`#d@qu5>djT|(eC`)2M}^V(%6@pBib+Ik+0oo&D1)xp+F?( zs(}RotJ~(PmQ~*3^z-OODVgS&AWdk=QWHy#t30F(G911(j^Os$$dz^SO)6LKpJ&%F zs6r()r+wjjx#{F5mDP*1?MBh_ZNsepP6p1MXU1Uxeyb)cN)Fz9UPIYivwRoiEq(&~ zhZ7pNd0@{n9b!S^w0q7s4Axx_PnIK7PVK9TI<`FjObxaNe>)7*CJh35O$N zravgitAeN>MpW9&oAjkYhUe0SMoWGEfQ@@~f2`}m(VEyeS&;7^y{*XXXu3f(L!V z9ROU75?_*;ceqFJI! zI}ZTV4~u0Cm_Vvu;i(0tKCZkkcAGmm;Jw0qs-#3onTe=9ELe+&mi$5N@UvyA26I&O zR0Pj~{?B)645ffzkpoLY1UxP+bv)NNy54=4qBO{3gtuh3)u{~aX;fI7P^&T?47!vz zJKf*SxMBL{U2yk^1wHzl!{~G$f9{hN(ZeX&%*=l4<34gV?Fz%V-x%+4g~f{xFAh4M zz_x5}{wrR;vsdD7T`@LUwaa?1(%N~S?k+3bxR80}jn#~z^Vwe%@*1vL7SO_YWSs3V zTXnf)w6A#bm)=WnrgO1+OZv5KwtH0exrL0ydd}2GcJ~FS-;9Rf09fH)vwD}gi&4|h z`K)L2fwEV)CdF;+epY-Ik|XtIN+a(0%VTenOtZi|AAH@}(c`c~jVJB1Z#5;r?i;rv zm;Wf5qM{@&+AzVT_@vgvw&_t)zrxBYw&e#t7EM#t^d~z_5PA%r2(ie?vaXW}tQa+( z%_fu>-Oc{ieF~>h;QkQdRJHcY*Gs}&N#dUdT3jQlyA<}jo%XRQT_VI?yyM0w>jpK| zPtEIma|&mTMo?XPUi79guX|8zd}gor;I5jlE+l*MhZ&F8vtib*LGLId5yl_kKJ}zm zXEnECcw^ypKb`Yg+{KVs)NhHd6)oJ=C*#r=V6=VqJ>@CQH??qD>^^$TWl&Eq0Kgq& z@mV3g>j;d=bC$&HpM5-R@s*u_dU|@->9wo{MlX)Q~>?%;xIn=7_8!aI-2Iuz)ZWwD%?F+5bL zL|NJIhGX@ZT`m%3d&|B05yrTGyK+rtTQFyK!?gOh6nzBc5Y^hxmhD)gIQ#x`RYOj? z2uIX~f?CrQLd>bPfL!~8!CKQ+r(5CmyJUlo+utMPY>j|o;GVPP%3P!Etuq4b*=3CA z4?tjV(Pa`Al)l&a|Hg2%xbzFPUh98%VBOcIBi2a_mu7e50z)Uv^l?Mn&z^p}XQ_>A zQA;fWg8`TP_T6ouI3dgo8W%+5IEJiV4*JfDPu)u2_w()? zBsA?AdKe0Q2c;*cX9B@aF8VqXeYc@o;nTC=&p6bAo!lYy z8r8vuRBzk%O9D5$EKo!E76Ej{n(DC^TR{oWB zFTM{UK6?GWHg>()11vVy=fFnBMJzM4B`{3%AZ(jKw%v`cJc#Jbo-_sBOk}v^IG+j#gJ{+1En%B&Xr%8s`T@AHeYDUv zHKjGJCex$$KaH}+XWPRCU&1QloEyv*v+iCBxpD^RZO~R~_!$^p-5AweDf;OxWiK20 zbS8bj9T(o)6zeqRB5&Z5t?~$#WS>#C>8o2W!d&z9O`rKl$x6{)5N`=Xk=ZZuSGsS! z(xHEJ@VQ9>1LuLUt692vER8VX`ZU{ZW$cgyZ>)_4QjhPGECpRvhxWqEh*_nG;WIZY9NN11}`;Oi$#`N`W}@Kw6J zZtu0SBHP+6XH0J!JdkO9>KkKwv^$Qk@0#s)!hz0HLD!MYC)oVqi2?9S(2$RLI8AJMzA91-u@WuE*J zdCRo2OW{^U(~CRhsxQy9UkqcNfB(m+@RssYVRL5y>-6*5gN^UHS==hH3!zrTtl z{_l^rEm3>9<$oXj-!T1eNz85N|4;3l7k4j;D}LKQ>oUnYzxdO|dU?r1s=p6{U#~im z-j@B>tFv?kWldePm4u;Nj`3Cw-G;4pf%BA!Kyu-cpeVG~R_R!xp`b*ZRg}#RD;VgE z@4eW?yh)HaA`k7eHKn855+H-B*xIt zwOZ0_cX=gYC>UP4Hr^+gI5Fq_)xMF5?xlv?Irc*ue?K!FozCX}yASaJxp4NB6e+jEF+$1^7uW2fX z)!&BK+oQN%d*=VYeEI*OtySfgS;pPYr%aCF(|gTNpZLGndkd&2x4wNClu$wtDak=3rMpo=T9B6RhLP?NL_nlO z8bPE>8YG7h5a})nNy(vm;JXL(k#o*--Y3@k#eaRSrOxbq@87krU+tQ4wxO|voxUp? zvxvEay@IiwDA@Wb*v8n#0R*&tXl~_TYzJa~Xr=F9EM{y7HUf}kjcrWf(7dc%z=d9* z9|T8{)x(S;Xp;d`$4!bU+HFSrD7x9K%FGLq02jUHDLJo*zM3o*rxk< z)~WIYF?rFx`*_V!5Veap8G5hapP0JU{SLjSx84hf+_7{hR!6vvO7#xx+3mi3iIK2LhE_X6jU8zRgx_LUZqF^yIAG2O@E*{~<6Lm@ zuqXrnU1zxe$j(AFJR@t#3`Qv`H31K99XJmxC;X=H+X}y9;de&-9v6O(j=$%K|F>q! z-%G9k?=C2RZ{mJ$Tz_xYf1hsrKGFGoiuL>C?)Pcs@6*cvwbRPq=i$FU1NcAjLla@1 zaoy9d9pV#F=_ztOKl#I>9b$wHl6;hpLYMy5$)7;_!3g#CLPz80ucbuONB{X>J)g`S zbc79tOURdd`9J&p3*sc7cMgcLcWRZtM>8QPrNy94^dalL+)+%?tU{2D(4lvbA@HH= zlkvA%y22vvmfgdsjgTS9j8~P8UXQz!E>iJZ__x7+2g&cm_&pf>9zB207{6!9-z$UP zOR3+>$KOll-`j-WTch85$>00u-)9E@zd9%3`9k2Ka)jw6K)$h~v!pg10LvGS^17O} z5Am>pSIc`dz))(Iub#LYNxC1s1J3Yxyq*bZwN}9VcZly-XYNZu8p39mrlcW=;8|TB ziq$2WjHzkT50;_D6UwA>2Z>mPdH+#^fPpxsV1(Samc6 z#=FGrV*y!>&p(w&o}_}I)w~UZEGWEdhQP{}xLpF0gxFyyC$v*%n?O4g?>%7|NCW?t z=2W8BRj<;i{S1IdNv1c@2Ku?5xF1{}W;=RDEyUq+gbYZd3N@X9cYIH)A+cUpY4>)# zmbed!CSgmS{RQ=5j)P}zG|C@mpwQqmiz7@Ii6kK|7)sB|%X}}l%pKy5P>&KQ?*^fDlaK(IjE1L5@&X68T`fdt zjYeyi`LyY*?J6tyC>7|p_jH*ceaeS?c+y~yi_gm(@++*A+bXJzG_JI-Jeu!=<*omps9vjx(OLoIDt=0g3_Draz zR`OFW z0)>0?-0)rHeWM$$D}alAknf2n#?foQgV) z!JIm#0x0foFlQG|_45Nb)=6GKz_|#P675y@K-VK7aC0E#b++la|u3!IRg|`(HPX4dTW5HYr^x*?^IRBErw~urn;4If^T#{}%eBXxd%MGD2?Qri{SZBk zn(4r7=Ll8chNhU4CO{Vw)?KeHs=ZxeogLuk34!NxFU|K`WL8(kAv;uOJLf2s24mW( zgUrV`=Q=pFygA03dhO*`aS&4)f2-#EE4uwBx)Jd5z2xKf-X7=l-?Gj#^)6@byNwEy zmAmxbR$7-i12RCzbw1hiTS%sNL#fLsY5!WMHxCR2_)qe9-pj^kC+EFY8&(OzQUK%5 zlX?xIpB)x9x393wekD04L!2 zSwIS{Fa(O=iSHqYbx(e2g2MZ&XyDU-lGYA)C zI(u!>)Z;VP8pSs+?gBqugn4d}gEw^e$-`>i--3njoI6ZD&S2A35cVp@8_8;OMkzzx zO-II|k6YE!$_|ep^*%&o3oX9W64^Fkaj(Fy}-C z-b#BO?2D71rJuEhX2N?P0jm5pVLJ~rldfn266s#;&Q!^#F9c^F!SRf{9KMtvQI^I> zTE(%yEzUnBKOJWbJMZe^(NgmGHsOdtd*TwV&2C0(J-+*%Y`R&l_gKQd01cdRlAsdZ z*fMx>!&&Vt9IhU`LHBX!bd&cq!J6wMxa$SoGZae)t25rhRqB6d{>Ew-)tu9Gl*5dO zN)yJb(fNc6GyY+ls`sI(wVMK5Le4Maaq*x$`0Flc1TKMVy~_`E!?r3i@8LizKS~}e zKM(e5e7O`z>1?vxaj561+Pa$}Tvj_cL!od`{;Z{(rU4(`!YEhRV?0vt{K1DoXeoFE z9<}9i@j{iVkYrW+cnMYdenx2(~V9CHGYzIoE z%7Dusp)CRMFdyNu7)#TD?WFLNqiDhr4Du&;yPG{%n)HI_ct$ zxhb57m4ix;m^~&Z7tc*mZJ8sc0rNcT_(OT;Swb?Z=IR8e3R}Jxw6oifac@1IK28I4UdIT$rXSXKflEcYA9o6WJe<+@_ud2RsEy}BlDSjh{j2)HolO~1X@leB*ECmkxWr3|qDO13 zUYc<-l(>)L_FAZ$>=)DFm;p1qx3e%S+#l=4N_Tsfr*<)`lVjl-a`8MFmivdY^GVQz zyevE>0GR8gN7cf%`?t==0icsB`Ck3PwZ}o{o@Y+D^Gp>=em-fe^=AYC79P)(!^(eQ zTrQtL26tsL7cgB$j|y44t%7$^EjTmBF5U+GdRs7H@up!I^dzPKYVPg3vk$_4Pz_O|8I7p+D8c;0k ze(sd<{;jfjIk+1E=hh76v4T0pIPe-Qx(+EbN>&onwK z;ckM=S91v~w z&4KWc)%#jHGO_I3Yte;A$jt~Scl}iYKA^_m$rM!&LURTa@3Giu0I_!KZ)BR+RnL&} z7qtG;7ZC8&fat2tE^%qRJ@VfW13DpxS-U6itHOsJfH#2Wy*f2{TvGv`?QZ_L*Wii# z)BQR(==LOhmK6tdI@o}Y9}DC!=>3HOpsny3)g|md+63rYUiag^tMG}!$eq6^2_$ni zAliiG4`=m9$)DDoTn-yQt|9lLwfZa1HDF@+i@bq*?!M6aU_c{&kfRdZHJ_^J;9v$5 zZ{X%CvXKTX9jVSu1$aj)F98Se&fOuo>wrgbRx+Lg9u0ErH`uNzjrXG(f;(CTs0OIf z1JwXp)Tb)*B4-_8Xs0Imehz#Z`a?bBRPLYFC!f|{syBev2x;c>svAs{j_?;SpC;vp zxvRj}C2;V{!KvC^+XA>}BGlnAqzbUacVFDa^LAUA)rkUTo;yW=&)*IYpEO(+bk@;5 zqx)korwh=LqmOFvX;|_CWR3hX_+Hn_l4rTlI=KK|IlMuFX6>%I@Rst(9X2pvraYWD zxS3RgI^br?6~tRr_KRq%7g{N ztqk;Luu^l{K|Xp|N*)2X!7qm8T`Ma>=8OGaVsIN?;L4MiY@37K8LV#pqT{X!+jbUO zvkvoTg!7nG^`7p^tX(TA6o(TSU)~3>D+KY&0|9k`wn+e+^47-luEDv^LaUsBAlq?9 zQlPQN0-h%yJi_qv%Zc@NZZL0}4_!oD*G&*}Pnt2wg+Lw0JEfw19K-P)5 z00g*lMtgDrZ?})IAXc+YI+XAX1CW5wq$&aPttJk~c%QZe)INl(av>@Y0Rs(>wMOm$ z4Xmtp!Q%&o!$Jh*pMmZ)HDN`>EW&=;=uzrU&l;D16=zY<&l5Lwp$GO*ZsT-_=XhT$|`Xfa`N^#Y1au(`=ZIw zbMV9;n~=j=JiFuDp`LO3yNtY_TX@exAVtt8_Dk)2byTRMJd5Cy)Z--1n7X{}okzg= zg)vvgH%(#vsgi}hWyhpRUKmPYM+=8Xcfgwakd{VmsH%N-sRxUsG-AZ@<^|%>JM|7Th5z&uH!g~q~CEnkX||21x`T_8A_Nj$#X>t z0sz67)5;yKB3I3@u~rRJ&?>WSlq5A0(f3-mW^3 zML oL!0myY-l!M9E2N$hW-rQxdfH}dNUr_58xH=OzHFn+v0AO$?4lH|3Rw0N=y zp4v{_EOkpEKj;8#MqjM~%Y+zo+qd*D`+H5>11D3ts}{RcXTE~nx8-vQ+_sZt;XULI zf{%9Hlh~6~nbQUn4b^g~zB_KE;2+IE-T+<_2fP%ZA(_h?05}q>tcSqc@d#5dN-qBt z`?}j(k1T(o-4!^pz}jK1w6LhJ4h^{lMg9Uwf(DH0Y&g1=ZQyjVTwnoVx%hQK8|z-_QSFI|4zsQWm2RY=$5Qke z-g>}cXN^wXfOH*o>q!6d)ZSbEBs(O>CvC%Xgzg$JVbAr@Op*uMs#~1AElH}vo*lo6 z8LE)sU!`bZHWrQ>?#$GHizZjhfaJ6(d8G-W%d6+x!uVGgE zIr-jY$RQMR!XBE!bWadA3!Jk_Cn21sq{}$f?f5^tmG=Afw;g`R!S6iyJr4XH2mX&3 z2T=arHz(D~`psC(L`@WaJn+5Fu1p^tAwT zZ~hb4r#SNR-Dk_9gkOf8bunhKl7+~U>aI1lLT(sqvtc3-zK|!sAxvIZ`yQlzN{{L7 zmd4RS&cu;a_x#&nZe~F;#4Wd57a~;WDMX@sLmp~=ZE|y|dt+-Gk*VgzbPX1vxeMKM zVF}wtPhv>S{Aj5`Szs6kb$JY59OUp3u+)kKxij?Y%!b4(WHALyU`G3NReKT)(h zjMTAo90x4yh&zS%g|deNn{?PB=o8-KJPH1kP(!apY|fZd`HT@Og6#2owd-P>r7<=; zw`mA`*cxih2w+)^wuDLuTufaIPMw2gAmb^G6%2P&!T@<96lf34P4GkmFQa>KHg0Js z)Xq!H>2WGo-df*nB~b?<3mol@ax8Hdl|Jl*59rr?SXAThkLF?5X>g1ytvytT9ZaWK=6&7$pkV6f3FxSP7*?yMeP9AK_M+sf72|(%GKOF6N7O z`N^SNs;jY++Tt2Fd-QIKfHaXQUJvwIIh`@%w?In@v-NqIy?n`%>z3VkrW2{Dn;v9+ zrW2FR4UH)l&*Y?1*}27-NWV`zf0}xnN@>xP(*X5v>Wpl1P)g{2od%*=BYd=@-*ZKi zC5vO{i>H4jW_;=ck zlXTtmeS6x0xFiy~@w@!j6FyzPV<@MAZnZy@s6&dr>s?5^KOMOpcT3XWvnbJZQ3vzg zq+M?n@CAdIz90>kp_;M0ql^#78q-Uplr99fQhJ&N8hHW~;8ET;w{&gN~-m zm{(E$LSbTMBr)sXZC;3`Q?fpt=X2b-(V5jpAQ0ZJNk78s28s;E{y39iUs!>3hVrFI zKlM5X{|Y5k8@mzKsL=EIp|acPJ;vDP;>UvVJ)I0Vax66|W*YB0y0!$V12ovy2u^%` zg*p&8GuaSU1ymRZzp7nB@rQyGw^wvhiiv#fT&X=I;=@fRk#um81-gg0@Vhk9+^%d8g|8qfxL-G zn*G>THNLQM`0avs`ZrUzb%EH9T>X`~A%hX2(N{>Gp2xAhuHmJ+cY6Xfp1MYFEqs5J zUSSwl+4d1#n%d!uqx4!q3ZM1+KsxtiLoLhVe(Jn%MV6SjiYRL*FY8!bUMeiQwH6P> zIozAl8MPTabS~BoB}}#b>1H1qIf~3$Uch9LjrC~7Xy^C7sH!rWIFYV8JwLQ*x4M3t zpu;2wwlHB%6D#-{PwDL-*&Lgb^42V-{m{clU!u}q5kGunLis>{TvCB3(|}`mh{m@k z_A{@1rE3%m6E$_F6dz{wOWwtgmRm2Qzmctk6KmG zWtgD$LkR8{dAzX@t9VQN`Xe9FyjZ>pjrA8F4JS&-?()k=s+vGT7dFeEnNXV06|{ng zqx|A^kxISHNzvMyWqBX8D-c@WMpMESFk?+mqcXCjU!?}8$Ua4PH~+?HGmq&q_d%?f zY~g**ZQJ(JS$|%y@R`z5#evU^d2NR3l;nxj6$3{7JD^G5hn6VU7;ENHH&u1=-+Y@y z8LAf!tWXBYEPX9!K@HPqa${V#?~;4yFK1Z5&q6SQZ17pG!ylDZ4W)`*G2sdM8)Abm zkA&S8_Xj@2jVF?v65C_+&Wlxc=3zBI6f=DNKp{H(XjoTQ65S)^G-ZR=yd1X2F$bxdX&AixfE-= zRx00Z>q<=RdDh+v5%&D}+5Qo|yzs`x9+vU^c>m%l;!SQk)4#4NSlRx)Wd#>IH_zo| z#hUg?s8OZ$sjz%6vtIt)*Hs9?$WAtoya*+IU9Zw`>D3F*)Cgm5IdsduRWgc7Yx=Mh zG|RdA_Jes86K-?+e#8>pmaw2HvIa)cZiR`v)&3wZq0GowO!saI+_v!)c~?AXrdN}~zxeX*P7 zJQR6w`VRA2_tm}nDYZMn_BF>3p2Ue{A{0GFtPtNNdnZ04tQ8h3Ojs;ydkmTnH_YYK zkpvM21ST`mar=*+;2f*H-hIHS>KolN3eneA`%+=b>Bco}XA^ z#E#bbzOcQ$Bu~zi{BCX+No9qh(^JQdjBRs4&u^I~CGVA;`LdT`1=E~7T}mW>zs2_` znkX2q_l=u$+Z}Ie%T@i27>B>E*sOkk{h4Z7t#&AygS5OH>pB`(tU%5k(R#eYqf6GD zgPc)xp@ZOa`PKq?34dg~S4j>n=|D&IAa`&xM?38>Jh?F6Q0zm*q)kz?tt(_>bW}g=~&px5SOc3mT6A6y6c29iroahT54~zH#%(l<- zhuR~}MY+9h`Tw2t(yeTKH&HtvuB=;Df=G8rP&$R4u{@BP?gDSz7rUu_HbdFRX( zZS04uU3m%RMOt}|rlVY{L5m-*A{KA#tvdT6F@g#1opI@M zhS8_bS1{FIVP#lYi?84zb1aJebsz*T!07Nd?9YH)?f6nfl|0 z8_DzxJ*6fr$8lPE9=xfwt7IS;)5>=ZSXD^7jjBEV?!~h;OW`8vkj$aTnk#As#;qnD zgOin7CF@9M`3$}M1%nF%ck@(mpTr8)`^&`+kD6FDoot1*AbTY|^jbe@X7I9!7j{m1 z@+^xMyT4e}Q=C6c*0!wG)BdP%&PfEbGW`8V{0Vhgt3qYvG;fB6l6|!hZFchKH!F7f z8meYlyzkM4FZHrIN<%ECD;d%`sdWF{s#k$WNnwWl9i;eVBIIFUI;S^69k ze#7I-q3g?emS%i5ZBWjwoXV12O#+VqCc&YGl^bR2NP>vJY1I@IO-;u62HBsFfcOrL?+& z!b8^hO*JG`U0RRxKCgC|8F=!TKY*L}`cN(f;zvgM64s!~n_5`0xfD6vpSs>Kt&Hg2 z*f;jxin8it%1rM;r=AbAx#zFy;t((D+Ccc_9uI-4oxH2$}7Y;IFe#i}(=b zzI>7J(B`d#3aJT=6r|(P^I2a@bi!Q@h7Td1zl75^(IIu{e2=0!|6Dhm)j<%R6V`>x+zuNpf+hAN`jV&h0&`$o~%#_M4bESesVpO$zY@!GZNOBQ(^98I_=Qa=r{L=(TSnN5-S zUV`++stDrEMbS!xQNH{otqC82SD2+{Xnyr-@_pzxM2n^TJ;I4jzQ|S)ju$Es$G9RZ zS*l-gCi?85ZWK_j+e13|>P2gO!1dT`O#K+FjPd5h6OA$5+k3K_>zbbt_=3VVcK!6j zM^1UFd>&*uQDuL0sn_lSm8l}jl^6^h#bcki_$y0Wn&O1DQV^3rv=o=>=oFRP=$9LJ zaI>S@n!B^ZZk9Y7zM3yiwphedpUU0hogc0A*>5%whutzQXw8GHWdLdWLu~eohqs^s zJ-GL$3wk~*S`?yN(1MCu^c{MF@vB3+TX{|kwIR<_pN}+YsDHS#=Y_)OND{Fa9qEL~ zO#YfeGT2;L-61*xG)yJXIgV&T9E9-Y_O%XMv1m^GTjKj)Hy>v}g4_bFjt(Ynk%2y8 z7M$^XY}Q8!u~uDP!gxN%V=#Zqq&6)vAZVxB1J_yLTD#RG@63Qih~IUO35F>lA^9Nf z#;z$X{1G0BfU=EL`ZkS%$c8%+cXD2Slq<<*;2zo;lRHSkqt#&7p)00Sl-?QVe8~tJ z5b|>U>(z5@ZBqm#AmwU6nG!l_bEm_&T(3)wWb??R@%}r)==ZxV;_4uA z676w9i@aueh~;#Nw?_9~XlR@hy{jR=^<1MdN00ue#?W_f5?!?K53Oxsd(m;c5>TcJ zn&h)q5W(Qx-bKQyQ3-{h9v}G^}->7&H7D=fX7*~2z4%)2q0dI9frhtKuRIw^$ zZh7BCQsecAgj&)o{=9@G@E1k}I@9}$0f^0L&pQPn@l|qj#a&-9W+$@|r_*m2O4}k> zeR+_#9yWcF&9O#RjJt985>*0u1 zP+xp}di0@PWUA~Y)=Gx25$7z$+Xr_~-_{?#axMLCfHTf!o?GLjwUAS@2fDBF*j8Y?W`)NF-U9n~ zZGt>)(B2CWM02TDnZGpl6=H}yIiZ$+u)j~T-2iR*lp)o%OFijjQU9e{)otM58ovG9 z6Sso`nl$Z?tF9azYO84Sg`$9v_ayvw|*+y|iNq?uhIt zR&tH_B1ItT0cDcrUm>NTO3&?SZKsL-z%kfvCU(U8MuYkOwz2UoQ0kltQl3z=TATLE z@l6ft@APxxYOMEU$BmyYSmrS)pLh;vt}BL}vZQH;pX%R_Y#9#8N~N?bY^^u_RFL`N zu4BO!L0D;tZ$nZ~B-ficB7&ZrRZJBWlH5;Llh4G#>`^3qn!KYoZ4#t08;!mz4aTYw z6h`O~@w|U`>)2=H{mc7aBX8flZwpb#=cpud4)yP@%0dqIF1L8r)$?4-5PLE=RcLy= zO~hA4=^EuO-(IicJv);b`Mj(*wOHD4!5$pV3JeV4}z}K0{%0%3XGn?`Tc2 zc3KJ)msLY0%W+k7cAFpks0m*An}kmcrs7Ftu>QFS|_^mRlq6=}Jir5ZZuLl^6< zvobPHoL&K0dm&+N<<^cnNl9B)dC~lnleC`*)rH!iiucp%!%Dbjuu^N8t0+N^qlP^r@0XxAZ!8JvF0M3S^Rwrw#FO<+}>T?41#sS6}-N4@6f$!=7AGe4H|r z|A;i*Uu8Hav*76TWTzFEb8er_QR+jXz-AMgc^27#q+7>Mp2>0Y2fq0}f>A7j8|Eu7 zzeY91F+S5bX~B;uK)^-2$-{&{BGRRjT7wypR`!Krn^$Y-Ekm`}7ZkK9lrf7(SeAy7 zQeek2_vYP_+Z;H%vJ>&DEF#Xt zLU#w|$koy+L2R{glPf*P?^oW6e0!EdUcg9YemC}>dB3;1+=C%@2E&QRu@%K6mDcHN z1s|&U2Q<+khrM*rH=pCX#ksFz_$6ao7wWyazg>nQ`0jo1ZLKQ5ExH$J$VD5C7pC-!Nq&~XY0(QagBAkW8u8>ZfSL4j zHG-RxizTf-Q0#r=w0Aa)-X@nB{1zO^yoA^W%2C*}CCREi+Q=XtA#b@eBdJY@9;t*w4#n+m2b(!>&Q%#Guo@15VgoD}vF0&9J1uB!;RYTEC8VTw2 zQaRkbD!T|PrkvUbCA&?ky~x_{U-v@&8)zxo5`k|%QL7E(@VH2!6kY9tFfm%pPB3cE zjoi6%7O^G*d0S7UUj4qfqF)Sw*yc3#8*bi1qEB;~v4t@`+_=W>vJKXs znE4^iU5}zZLh43u^mx`h9-{V@#EfjRY}d;f?}o)eWmG75Oi`mIosTWzMrp8CRY)KcIU0HmhL*WNiJ~tLyA-xtPrK zUSGVSr4*fONRc^4=aMyxnmZ~!Yq$PlN#xyX$}$0eCOW768wq6d@%B+}oB4;?qC&mc z30|wwbVlzjq4hT1SKa$*$JPSXBpx5R*pGA2su@>cX3gN@6d!^p!0#4TlLVU1 zCTeVPBbsaLmHU&{k(0jSsgFFUtkqP-hQ#$%b>FmW8on13U3!u|u{qXDM*4E{gphCj zxnQ|gpS1MmW}jfM7s02oaj6;m8%^|+H;_bi>}@;9X^bR3?z~c}edbl;BUe!3SUxK~ z99^l^aj5C~edVovhR32LqQJ_m?wf$qXP(d1{Z*}!4pJ~q-YqaAEh+PUv+c2L%>rjUEZTHh2{gfGijH;ze0*`c|^)Yf&cEix~=dF zq!|{-{6nGwO`|7qgYT#CT~VKG_1xq(<7U+WX=)5RLy@= zgVf0+r`m4l8b%EhII)_>XCav}I$~Ov##07c<+bJ?ZVg`V7R_LUc%1g-IlYP!T0;n( z2>kR+yzI80At^+~li^7*5vjhXW;900i;voY!Xc%6wuOd=pF}&qk4|L|DIBYEE#fm+ z<_WLeQI05cU9jG(Ua9{=V%H~jxVU0N+0m-*wtJNYZIe|$XH0Xy=MHyFtWfTqEo|&9 zQHg- zpB2(z($2!HfUb7)MP*y97{v244r5y&QQc5wJg&ElWH`xUsFjAedD%>>d~8@o`Ta63 ziC30U*Yt+#n?#E?SSg+R^a*EJ*Qy%2GUUnU#yYCA81+OpA~mLM3-R*ldLJVnn=hY}3bQx(C<5LSv zH?Q|Ob}8@8r2C242IHR?wDw7uqz*M(>A#uW#Dqzj;37}qa^jwJwNkK^r(pOPGB7?m z;#p`WQaY}NB`>(GAD}I|_o6eh$)raOuc8@Mqx3sUs8V)a5tA6Y=as%MLtCadz~@+_ zjc=9`u7TW&kCeXsmCww0K@JuF^*n;s-uNU;+GYqfI7t_$HlkeTy-tW-+Jh&kWuzSf zu@kjV7^`pdwhZAt(?$_0NqubJAMYUG>(7HVscXGWIha*Egka9QP1Ni$#77_J%hs7# z4g*6wcASq=hEMgb-=whg<;0yGtBvi?=gz!G$P|6gg3yOE)3E7Xi_PsRTk&j|cM@2z z+c^+FlLLd%M3^N9JZmiymsV^r6JX@45IsYcy4phG%I_jw*01(3?x9^|!x_PJH+S4$ zKQX!Vfyu>XXbR^ypD7yKgB|S*jqO3eEolmNU_&Ki2aqPSg4jb4v$C;^1Bm(jiZqcQ zucAL*rL@tQ#a$dElpKJ&&fuaF>>zgFBN;^@A+(>@tih|*xj`ad(wcqha4ad zcpY$K8YhVJ;wfBA&e+IYUj*y|(qsWDIeEE2JREF5KcavfaK)NE2>w+PKuXEM&e708 zLErAYk_C-fS>M1O#H@tId{GBt{mJCVJ#egWygyt7_kW-6f3GB zPr3f0G3&pfG28-w(byhtOGm&7z%6$&=0^4)O?Xf!g3j%us0~p1X)w5deu$efnX_9M zI=g}0?7?olKSh|;pJ;%%*+AUffNcRE{fkztoJ^cNoGd&)+JZTZ%q(rW*x9VutpAM2 z#m&pa%FV(GT;6wqYh(&`vEgyyv9PlHb6ZYsZYCB^7Ve+8R@SaA>}(dSuI8oy?uA;w zt$!C(xp=slcvv}j0o~4l9l4D4+1R*QO`Tkg|I!$a476nfLhigVubCOUv!jWfr2{9B z9)CjS;NoK9;9=+biOlNyl-HHb+KP+&DfeF*vvadB0ZrL}w76{XzuZ-L5#{1m#@0Z@ zgP0`&uPcC9&yxvwX9_xZ9pFb0%O$@7hWP2XizNRu3gG#Fjsjdx_z&-2`pVWnMN#-W z5Vl_+Y=6nQf13*MJ+Plt*x=dnhdBNd%HLAqxCHW-q3=&156w*-?SQ))|G8z@E}4ey zFM0JRsK4dId5O=Z?E25_%XJ9^K5+h5mf^kx0uQJE3IzC2{U1L1SE2j2HsQSl@~vR+C6_J0+-f6wJo2C)CvVas|cZrT6q zxMjT*xa|LR;IdwdT=xGua#=5hF8hBSx~!LCm;JwvUA9ZH%l@Cn?!_eZrx}3bKaJgA zD3>yT<6p(DH2*408ar;_<9k(l!fa8yuisQ0(UrHyqvGOL2TzsCeZmD4m^X$1MqSV0fH~b;H3)` zwhNT==|mB9J|6%t7bxc=GEjm?CGc{Aaz3a5r3;kvVFf5%pqwYRBIrCbftL%E^V9%J z7bxek36w6loCgO`y5Mr|9iVis(WMn5=g&<4w^YCA=l?OCFHEidbBVzDb3D=fUp2-* z;QuntTxR;QbqC@+53*ki8_vtaj=6)CF^E>)$=J@x+}IgJhX&j!ZV&7yE&}t%Mumx+ zorjwn#KpzV#KpqG19%SDf&AFno}(!O8v^kkkq)Q_-=uS%N6w{QFKcwstCaOqU@rkA zj=qCA*aq~_3hZoXrf=u)&snfDv2wAovhad9xwx6wxY>FCNaMV_a~c;Z1`xC}b^`sR zcfsjA87^_UJmy_+Qn4{IwzGH8w=pueF$Fo88G`_On48-C;&d_8{Mf^>GqJI;u(5K2 zxVU+kSlD?0dY5f;-rqT?izNF=>Ic~iQs+r^i4?s2bGW%61^4Nnj0K!P7#cqXP9Xl_ zu|Minbvua7qrf^@F%SwbT4R~4;7ba!OMT71#mEd?^7<^cYf~j zcYN5Gcvv`Dxw(J=g^P)ol>4bIkCT|#Kp?N#>oQ=kt|Hyyui--50uV(yP))g#Ra85n+0ybKeAAe5@qFi z$i^iDB#MHuo%vHUfQc1I!Q2LN;m>!e>w7U>ajC%a3qLfuIA^&u<8%ESu7Lxvi%p-rql1;XjWKX2^8@Ec z2NyU$3Kuw+=6tT7L+L+oMD-o?t-z-6F~Sr$#=AKDx)@o2()s)ZoUQ5GSxVWMfZ^wF z7v2A?xp-!51OiUgi~)!LI9~fX_JM$O1135&=AU#y=b8W&s=yFtYzO$s#27e<`*DJJ zf&G_903CDtr&ju|!0fGjo@PILlhp?@pVrt$S3-pDSGaM(-SWfHvc@*14rZ(%HXb%E z7Pzsj9E|Ni%nz-AlSeUQL$DDr#$U7n9K+59*c@cigzs*it|{?nbpBZ|DWv*t`{B;gwp0?(>O7m&e58L2pRZ zTGK`y`nFtTj>NG1>v%PUv}8mUVHVg?cBetq4uj8A^vNl9&n1JiZqcM8r2CNT_jz4a zw^vtGbjd$AIPm-I^sZ(H$2VYDnXkC0 z4(moaHk7=|YZ5f8rQx^Xk3z;Hi-pv&si zYar%^k8c@IopX^a0-iz-g4A7>PNUIl!uNTtkdUJj-XT!WeE+i44${{_@S(c!g zuFHGZi&r^rIy2d;s_l~uQzemW5X#YvM10lLWsVJbi0wDW>Ezm{3uV*E?Dk_K8@k+% zn*tlUdAIJ4cZO;2YQS&}4~3O&@R+@}g0~#-Au8NvQ}V)Zp&;E=70j*m&Jf-j$*F?>l+S80jW6Oa#E>)|s$<>H%`77CG1sqFJExkJY_7r`4 zEy}g8Lf=2cCc{V!79k?X6sI3jqu8V));BP;n3Gx>RUB(_>uGd|X_pjZXeq+1XT=PN zP(XL&c^|}rw;;mK;76R|FNK$VWSc`z!ktPK`9A)}a6{u=m6_nPX450c_c3p$-7~OP zbj0I1hT|SNhe(!r0^!AGK4n66`9W8J;S1PXn3#t1*6tjnZd zxA-)s9N#(hMOnk=8EvnT#-~a;>2#_MpL&jMsle{X$TV;*&h&KUAKv6@(I2&%(|t9oR~biG@|aOP@!1<% z-{2h4_R|E79bK)NJ1#h)tS@?NzkHBvo;|DHl`Lpd#=v@7$E;WK9wQ_D$VF}Ww5fJ! z)60+JI@#*CWTaF@hy63GV_`Nt`A<$XdRkJ>zQLIgpW{MU(viAG+>Q346CI3M7Aw7Z z5x%?!bs}@y`lA!ELk4F9*>0G2^GKBjpQpDTTx~~r6D<}Te1wO;(+R!R*4}wNpt!_0 z4iUmkDcHGUTb+2Ly3>L+;T1~lquj^2Z_uQ0X~%l?8{(uqbOmF+LU&6nV&;{wBh1$ot)!$TxOaRIG>XDFTo%Z}lE>_iDcHV4BF*A;Y8f zWj#M(r`MSh+dI@rLxz0V_fgJRh7&EkUvV4;G+RV>JrT~!CdwVpA5=!pHL=(_uD1!n zkJONDPHb41_{95s1Ih6Q@kip}GBSR=ZKT|Q=C2JFLw>R0f>z6~)F(!c^am&JzoUT2 zzfzXNdKCQNsaXf%x4R0>2|;u@2GWzSyqSnGtu~2WGY*mBSbB0 zt!EueIb!43;o5II+{~bAlbxg6fBZpBUATjDxVv~|xL~uDuXSj@j#zJ`$Hx)G-1)&= zL)TAk%3map6xurU{VnD$s~rv3k}0Krs&pvWZHc(6Hh!#8JxlI1 zCVO9J=^k|{md(1|l~E7#rF=|baJuBRD&>jY%Hh+{fmrBugmAYh_Zdjd3Z?7w*Vw8Y z^ICJzJ<}6bx^di{f-}^2C`j^N&gN|c%0YL=cd+!NGH3*IUhFfc8AeDlFo$Ia7NafV z9`ih3l-W9Fu+D_}by5pIq!r2%9erd?sO~d^g*1W$HjB|GGBLQMNCO)gKdP3V1f(lb==x`|3Q0QAN zD0z7u9o6{Q^_aQW`=~o#Wzr3Xa@-nZl<1c64z!iO29})2`f2-zrQ}As_oAwD1;aU4n2yk z@v2>T?apcDGgMG;{m62NJ3o0WNu8JRJ2&#MbI+Q?@zH|5907Hypsk)Cx2nC`)f)yk zZU=sm*8jc^dcyBiAv+YBtTpvar^0*f`H`x$nM!}pi-{*L1$9kWpl!u5r7w0~(S91f zFDIo{PNFMBQPkU@FKc`jGb?UQ8|R=KBV|RPM*10NZR)a`zSP=$BW|A zB6VnqJ443Q`|7wPjO<*zq<}EV8=IoUhu0IIhJKV1{u(59aMLqNyC;M{0aNfbkr~H=}}La29)=Au?a@k}5&{ z-M@hz-_4*|5J53&bR&}Th&>?jJV9|mOKKGom(1k3a^)%G*Xx>rnl6}1SdIPIG<;*U z%2Lb*GL*d)@c}{`ZX?&hIOy4tp;DQ*xc@K0-T^$)W_$EaGO=yjHYc{NiETTX*vZ7U zZQHhOPHfNZ`Oe<|y)VwW{q(cm!m6rO)wSyBu72zHQpn}<7zX2Bk@yKqjheqjl}f`( zdV{D7L43fEOz>yzC+)kQjk}BP-wsabhkl9(!^fo*5}##XZ6M2&{^)Ixgybvf)b2M+Al=Uey2V5#R#)qQFjEZKbZW1J&d1yZxC@~hnChRNSf04 zggxXn@ou9noKm|vGTdQmMiuvGLWv8P4*;)k_5~FXKcjeHc~gHw5JYAU{^|$WgCZht zgb@#}5lO&AevkMZWZE}o@@G*dg-aQh<|#ZWOetE3a2$daZP>Rux*S(6-*G!}`9lSN z%XO>K3Fo37obHSwwXc3ddj5%@8OWiS@7Ig()`yh|h5+@8@u?$f@s}2Jx{hEqG0WJc zFO8jvz89|VJGlh&Mh~P zR5Iw*sKZwAVbX&cgP}v0`}ntbXUu1wAG}mu zlrB=&5+_CX(B(Ij^Qd4ER;WCveu~tIpGhv`F5}Nhe(G!qtns0I&(BY+WjHJP;9HV5 z`_PWaF!SM%Vz?flCkDLL5k11eh$9|MwePDOJT8%HSHH&%VP7#40u_XQ1fxMy*M@%A zot65M=onN#)qeqUQ)p?`O{M6P{C0z@RUrF-$R`ofkFO<1F*kAp^gy--te4-t1BCF) zYK+)DCX@8rSXE(S<%`hN60T6i^y26De$y*6 z40A`x4DsvdmI1bi3J9ZJlQ` zmyWPkUD+FR0N;#IyWSR|z17%{8H^5py+ObG5_$WTBLPz#=6XmOy0d3S;w{6z%Z>Xb zz{R1{xzCb|(oIGmFB@UcmzkI>l~I^AkAKE7zY*a}d8v9sY5Ab1kio_oaCQUl4I_Yz zHXV)g_8s+|2k89=!pa=@9-|5pLiWw}KwRR!BokM>sK&%4W!H#3AHi^w1NP;h>J1L3 z7^TC0Sh3MNb!7?q5ieL-%O32u;CihwxYi}_3r)<%cktPv)$AxXz96*Uq#M)s`aYClfa?Y z@)QGe9gH7YdmkJ?iqdZl_5N2(9V{(V5)B!E^h>!dwD9`YfoBzKxSs|a)iI*QW;1GiNs47x!~9zog%P;B&fV7N?8B+=Bja?|MH{f9)JTmH%;;9hl+T%LBJdx?y2j0owahpS^%heXwCgs1 z*Y%N=XP(nNEsXMHv|F5MFnBy;7_$doW2Y5eBKMp9RG%115&~IhYWM*yXz~N;%}682A!M`0GSNjZ90gQK@F zP2mkHqCZ0YyOXJ|b)+;f-Ub&E=*0u85Ca}D5#VLdU7 z25)=%3Sx74Kk29F{umv+S`8kg)~|V3Szy43Tj{JI$0!c?}Uqa`K{}b z*W>lmclTP?v$~TP@|eT`zxclHobm6d3!Juq2U;(Q1ojbfGM!9}xK@lut{T1~sJptd zgZO$@_X~|i6BBu*p-+vl|Lt|XQv+UGoAqAO$?<*NnXMLvh4b=mpLZedW5g z>)oA*vj;6^r~xV6FT?l5WOVeR#+ zn(Vyl@15xfsHNi80U?7e?(^wUoN(15nbQv7ti;nn6-Z`%iGv)B83(xLQr=VBf>gJw$~6Vm@|3xnB9A5?c=Zbf%s(g|%1I#6oGcfgvI z_6{#eHXXz<0N$6ywF?OjYw67&bl}aQ6VsV?0Hc-l2BtB<+PAU)wts0)vX6(W-X|O8 z);|^A(`(s^<^Z>!V?akMt^+}XxH2F$2nX20)5X0G;X%CiR}H78D8Rsa{4u}4q42I5A-5Bp5W-+!yP8uWshO(PIGve!Lmc0&`R zz2`fK?hbSdQX5&==|pac{VF zB)yXto>K{LAiG}RL5@AbeQkTrTmEcXtZuj-!H;j9VeX*ZNU{CWVb{GA;m^Ce?qIik zFE;zS?gT$XKYo%l|9nB}jB$tE{{DfvE%E_+i}!-ME%ZV1fq%>5&f|dkHF)d98L$c_ zj`Roin(zy3TNc-!ffGOU8L=nm8L1}#0ZHEe1Djv!1GwAYC~T*HB)sLe@B?b!?S^V! z@`Yr7XP0GA`G#U};f8DfIjkp?AQ$HL`sQR%+aA38`v=5GgFWu8_zUtau6OW@JZGFc zif=#-l3$1&;>Egd4&|gIq)uF<}buh^6gF z>t_(ryY=M{U!9;P8*Je?s51`z5)OTFcKrmpu%HtY*eGAX;hDbjo`NOwV{eWYbg_hR z_JoR3_#*pnhz7-s2ps%5wYUecQ6)y1F}JJ+;I`wHIgS}~Dvih+72ofm`(nIu(pHyMg1 znHr?_cDG)kRHMz$@!deN34zD9z{u~4ouc5|!4$o6BS1epRljQ#t$zF}w1l%*z=`0d zS?WjZ#6h|0gK7=s=q{sU&4r{E7J^4L%%wa)OV#R2^5rXDKB%l3Nz;mD0qmPKWp_cL zEbnExNGKC-f==}_uLc>=6sKveX)EU9@x~=7FA}waVL%T%BZ^AaE-n3o`Z< z!eCXo>Q&B%dK8cH6F$g#CPIaGiwo#4Om*+|AG9dlZj`+sjB(CM#*$-z`J@c#CRsd4 zS6V|4*?=i0;uqHB{yr$knRQ);d1Jc#9y%l*Yv2n$jE9L~bZ#{$*aV z-3KnMXAzBBh}?al(tjpPMjMkqZvDpW1J%V%@CkW98>N?@b=voO8j0D#cvToVxBh={ z+HB(Wjy;dDgR#dxV|V81(7r)O4q)ma_`SnvoJ+L2lifCIJo1AY&NWH4<8?5X{z#~eV0 zotRB$B@t(F{3}k(#bQhk|BC6kNo~CVe+O0~aTLeD;>27ihWzlanC^Sq2*Q=kEP&@a z|MgdJisLyh68#kpG2Dlx!ZF;_L?oe6xXg~DnZjc5SX{=3zqtMtFF@pij{7UP#EBeH ziT?`67@2Q*4EraXNfPom z>=1)~XfF6y?BUXl&ISAx{ajkD`}6>lzD}fG1+uX{amv*9en_jw>)_Y?yms%zjk$eM zTb(-4*2jsp3)%4SMoGML#|m!F!^xQrX-A zdrq)WTEu1%Vn>)qYDe@(kx~{Z_0p2j5lj(P5xNl=X!G=(Z(72iK9`3I%;QNUn0}!K93eKCwj&A=d62^VA=a?`KaxWq z9vw}~$AvNbF+ngtDxvIaYtS?%soMh2$C{hfA9GDFgPeX{>sz%V7CbHAU`9Q)gp|Be zFBuaArKyWN?N9QB-d3yaICOsgHh%D~xF!_i(ehD@!qy(}VQQ~u`)ICFk|z(4H?Blc zx^>6ph#YBpBPUv0Rnwyvi(9r2Q#=^UGCtVSQHsrOjxFL+SF115udqWDORMT;7OM(i z%y7^D>AlSd^(``({bIHZUWox&^Eb~~$Idfe{U0>2$n)E}9^JuH30IypQY-J!JHOz; zr0!)YxPp;S12^iJI`tWxT1KGwm+vk>r6XOcI zqMF$j&OfboadwGz<#w4hOgIzTKI*UVb+$s^%1UM~@0SdMNgPnus=D{qE;}RHx^aB! z87^q<2@LOofyX?h?-7`wzAM&0@>A|~Ubq$?ph$0oYfdX?tJy03D8ntsErg|JNx~X; zE|N7-Oj7|*k}FayQ-Mw@&8JpaTSw7#4EoHUE#4LQrW*Ef63lCp-wRk>{hTGjBl;=B zG=sIYczh|#qFv-d*DbzQ*KYe<^Rali$iYJ6Q;X0oDPW`F!WNrpP!0@>;?`5^ug2fD zf;Ja^7BRIqXY~fXxyI{@x_PeIsk)-H-rL$iAnteHUxk3%b0w>_Qqu}gny@YP0LfBC z>2&IJC7jiTT8^xYxE6B^MraVnZ7bk(M1RH?1!9-^YPdkK)t2UU3tJZt8ysk~tpdO; z#v@!`A<*qCXUcvy(QwW4@f~jxqrmP-V7Up zVMx|1lald~l6BJg>lEISSy*#nm|Js6pu7rnn!-o_YW9^*?&B< zULCja{R1F5D)nGPv&m-ghYl&54JU(|sf{E4ciq9X=oz%UgH^Z<& zYi_N}UvbcKHnrzf<#%@9#WycMHmd4)WW-H&X-Rj$n3H zt2)KcE{`3mjE#Bc<;I(0P1uWjGLTHCUH4SX2l-z;Pxqkrx5u53mJ{%vFGl7FqeKa)+&Z5 z*{&WjetT$qtI(PpjWLacp$<^AQWT1P1*%debf^U6BB_|pZba&IvRjItEw?g%dj~Ex zqYZcLYz?D6d};&ID#Fyvd+_vqJ*YsS-i5JtU&5-4#5pLNO#ITye8%kyi2{;tTr(AN z-1^zlyQ*dQPdPYOBZn~+u zuei^-&-u?4RXr-^%jYTD2+#=)s9_2-=0DFq=TnMnq;?X&4BDx)%Hju1V~dp&rc-S}1aiI9Aekf5 zEi#6Xf?eN4aLBkxoNxp9b^T+`jcHeG8l=vR;32RAb)R0MMr0;Rc@DZ#UR%X;xIEg< zE&}fE=86*(=I}J_afb*jbQElx6Oo)83ggO%3Msg?r%Wmls>JZez?IWVnUf@`S%#16 z3(;9G)Mm?}9_!UEUA)Rxq*m=1YKcEqR%dH|u`b6{3BYcPU=$ii$U6hJS#tep&8@9T zkH7m#Tl|^-BAZiSRL+~c%2CxhtldDB3NBTMXumg5o^b04hs|755D-WEvo5PrS_xp0(x3^OVW{^ZEz z)t%afj0N_>Ih+25dDjj8y`POUPvO5=TE-1X+<2~B=YihiSsk?SfOEDB7a9|2H95rO zjX%ZsmVSp9WGSqjHlS;iC55lFPthQuzWzWtM>{8gE`f|3vN72W-W(>CjA@pk&CaMO$ZBXR{hnbuPNny!7J2klgYsVY!VHj|}YqvNu*o`UXy zu=T3+@sQG*UH!f7I8P@FF=*f}*Q!xk#Y!b(YoqA0+zgJV3NOUxcwkxX9;srR{*gmH z!`AVl=sG=SJrQCL^4$qV2dfGyc>`=>np=kAH4G}K`A;bJ+A1Mg<3~joA-Y{) zeVGk$!<$f9Jr?lY)%D&M6Xjqw; zU-1ASt^^T%_1BOnIz2gK2GC>ds%KC+V)X4oI+Q9LN5(Nf`a75J)o9MXACZUO#+Su2 z%EZVI{t}P=RZ|D=;h^^9EA4%=?LST*tQLg7M?Z~+`|futy>5!(aISUyrCq%DY38Wv zPGmF{Bp$qARL{E2OZgn+y5Ui3GW1$}Nqq`YQ&N-H)zX3x56|8P2zB9fiZdwW)Th{I z>KI^ZpzN0I9QdmImLDt4w1=N=n)zqYUEQC|I8!v$wbeJ4gNCLkBd1DVEqq$^sq;lpd@OdpJ>csEWYv%DMX;At$rR98kkZK-j2W=xiPiVxa)lo6UXlK$dyAN4 zN@GoMFsnz76}rPyW{AYaF(MU{k9$w8rF~Bw*t*th!UXeUp4XV$!enyzjLx))+y*VmX0+fb)eLB7n-)AW)JoTZT!(-HWbc;4o6kX?|a+211gyqX?K zah1VRUSU1DtCP((fm5f|*<|!8-o1DiSy&+OeR-&?^7w?``cU(}q8mx>k{gz5^&Agk zQciD&VCeo_E^4sr3e}7#3rCq>n)llEM>v{LuUJ`I=4$RoANqa%9Q@q$2XS%j99K7n ze$U2o+{~*Jqvp>TC( z0Zu>*0G>pBMf9Yui{I>-yu5e?b}3hXYwnhJMN{(Mk>-tIS6AHM~g zOWD_=2C*Hc%d@LziD|Qz#F$j2AHG{JL|#STEb>wgD86c+W0KFBJos;q?#aL>3f0}N zHaR8?^||Y@oA#yx-HVZMYYV2si2@r_i8-KQhqwU7XNRHa zfSAMDij{>k>NGFU^={bk(65WUpTL_hJ-hZbdjY zL(yr3eWA$Jywb;$;JuWAzuz)em#NnhXgStgC{l$D<T6`+F#iz&cR(khv9vzQY%skzjPL>U=<3EvsU!{coTZC zENyO)I)9VxDUG*f=c_K%q+;MmaaFEH zL%vddZ+a`8&3124MT^<5`?e)mTAs2+B&yLRxtVV+n9`}NQmu4>*n>VJmEX=cx1`2R zUv3IA(=XC&SZi8WtL3iYuJIXWT4Mj*U3j*W6c=sUDyT0#4@5W23o;z=O=1_ng80@Y zLsZ+}tg6POLQ$It{TvUHTRZr4MT@$YLVP3Y%GlbT+^BGu3Hg>&bj7k(?fW%~+BXYh z7Eut;KU7l)3Ao(hn+rZs%Y$~2dVX5mvt2>9r@oILHmpyvFN~;`->N52TIr*AgDH-} zGm56l>DuYQ6-5)llN8UOJ8Tsg8YolJ>}qS!SIU;p)NrmED;uhsYFw&as-8|0(UWA) z>a=;;V<)Z@weBA+-MW?RgWN12&1JCt9974@`klGDsJgg(OgyFA`*VD`vx+nN>Apvq zC&R2s0;l{~zf<>2#&5}s-VDjE1gKd@nPRd(w+J6Zuxx0z`xPc6WP7fRMf@>IQPf!CGm0l;=M_K{K1kfK{}oDo_2|h zkblV=iam8$D>JPof!7S5!l*;sP=r8c$z=8$4*VuP^^!GU{FdQ8U?Am3Dt1nyE%Vdz zTBCGJNOl&Hi3r0LJf~CZBNIX3C7d7!_vq)^s=b-}FK;Q>gXHVX=GQx`ZTGV=UFnKy ze8qWUJbO_7jizFs>b339xEIIHvg^k2b}mo2>RH9psn4JH>!G+w5N@d(3(rTL%i zy)knBTWD!iQgIu<-2Te zX?-}4946HZHGq4o*Q$5oEJP1-)s3kGY@@ZWM^#M0**tk?WE{tA{hYfaC*5pZ6jy+` zQREG?>fxh1Qrz!tK%xk(>!KfC3W7z*T?)gkiRs*hu1TryI24}}(?p1mPs(&lkmdFh ztENjE)Ue<^-roA@iZQR|nhq1WxX7+P+?4MXdAfZ$M!#Xd(MAO%UCG^nXH4KyBYRH3t#Ub_n^5pk@)1`)+vW~k@0aZd}4;#i;?-ZX;mFJ;ADij{(E-8L+N~>bEsLO zo5=d;g}iJ|#?t2&+ZBya!)AkUh46FR^|ST8v%B8&$8?1<<%4Tz|0N`i<0agci8I?) z@oI&;Y@Qd>TU~gu8QLSu^PJgOT=yI;7YjsR7JgQa3xA~P(#;7*Fu0MkJ-5M(rs3Hi z8H|O6_g{v;>Jrzapi#a#rneCjddWi4%d^hPVO*mnad#CXG)TC|j<{!xNX$V{8Lt&j zonj~*l{-Da@o%Z&J)TK`%;?wmAuV|fi%2#?ojhg>@s6RNfERO)oyai{a}9CrP;qVz zIngk@fVWDaXIdL;+mWX6Oq&6tVajT8h*@9SpD@O&oGu4A*XQmTGcN#ZhEIQPKb!_t zVre!q&HpT^fP7O30PY&SI}C?O;@!;2YQ}ZtRp$C8Gl2%3DOG${bSgm>t1&6HzLpj# zkV(XX66Y3+YgvQVxpr&UL|(+We>Pl#An*Cmt&yLJ*X>8L+PT`&VqCR2ooKcFYp$ed-h5@+#kE>KyGky5 z>)y=Ws;5yP7y{gITXI{Bwk}6I$HG+micC!#KeNy2o7ipiInHm6CnxCNK)-?BDJLk! zqbmeC)Jt&9saz7SyxUZ#3`3G&@%eBe5eMD+jZXj_T%c zmk0=n&F$goOzB1?pqb|dZ^<(&zO~|ub{@G=L(z}{Q_eO7@iT&_q>fa;u5M<(jYrPl z-4LR4IWhO^Xg(MxP%uR$ESvNNQ^4!ge@c^)zbvvq)aiZHgq#^2Z@2HSw`;l@MrL}v zXT0cz9~@5T&0j|h%eT6n?2S}s>fL0dNQQ-pNY=MBB(VaUa3oztws#!4B3m}|L zvYiSCbuF`D_cbsD8mEF#yLtL}%s^t~&iK}Me9&}{kas~i&tkCVE0^R{q*kO^r5&Xn zrDqhITSJ0MDSZ|O-+RB9C7n@@yK_6l3if=?+|F;B^dVvRgY@tTPand_Q<4E80%dh99~ z&q_!XG=71Rxm}6d1b0E7l9@TPLf}OI)2NTFT_URXivj-@z}L-=$qyuanO%!+HQ4hd zEesgwWmhk$&|$oc2rcR8$**XukUNv(!^^=)lBF)0KrFQM}=!kOc2+^%V71q{H6ULF5RBLQ{`lHIi?Vxde+l7-XWC}T>22TA_5fE}P8NqsY496@r){D(n3kX0*dX2%IT8k35#-$vzWn5$a zjNwvt5U@p-84-lM`5Z{!l+Jpf*gyX>RsEuOohfa7okfZ++Csa@?{a!rYd=s}F+Kr> zrG7Jt;&uHA>q3O=$LIU93`a8R!ckRPt~KZ?i9!FfW){Zjdxy@V9;rwE&LIa!7>#bc zl=qzIB|J-$Ca!7V5+r$GQkQ&lnW`9FTE6VAL#AwynBb%sgd}HJpb5*W)ycvIUE@-* zB8GbDaOt^90QHE9ezsxpu`BVoXCRx1jdJeL+*vMsF^Z+`;-2gFtl$ax4y6csVyvkh z(=q z^tKO&?>-ZgN{i>xOXW`b`0%o?t8Wiue9h;JMqT)IKG>n7$9nw(+u36N0>`s52ubd*`>>zP-ki-!7*Qt@W$Ws}t%#>dt{_G?E!=DN#;$@i0L06TDX#vh<)$ zTN4~TRLCrx{6?vw;IjNEt;^NUZD<~C>%T^ZqGHxBpWNA>NIqvln8~aDObAx!!sKobAG znDw_B=ec5<<;nK>2-o9VxZ{NW&CkokmaFUby#kjBnSja&#R6L@B>j)bm*k?<7?H`G z=RIzN2xQaxBzlE@!Qg06Iz8nQcJx%W1CTizQIgh^nW$Ttq>$_)rRftt6$?%K*wTLf zRP_SA=eVejJ`C5zrZtgGWL9P~O2>v~94fEpNm-~$DtE@X!~0A&Or}U0cUxp0wLG61 zM}d@?0#CVPqMaLbGU-eeAMaxw)7dS`S6!ghG1`dyuK(*q6-oMv?L~LW(*}QAq3725 z)%7aDbn(UYaQw+@111^mZy+|WH^XI>(Q|G#-LjZ6o+a_6lErxWt->F9wtXOy3Y3D# zV4Fk6Uz4Ig#Ufxdl_*8wRQI#TT$p~Lp>35fw$jHG1Te^d)lMZkCZdZ~RxV&(QCz)1 z?V~>oxg00?&53j?YUDsMCB3f`F)n$GHjEo zc#E&W0h_ny#hXcO+Du1DB}Erc!bcAcs39@WI^Plcj1j6Lx? ziHX39XOd>cwWN1oGloC6@^rt*B7CFMwpJ0HQ|||CWs_?``g_K-W9VmrgNK+p)qT&?4R? zzM!uu%~sJ`(Pp`+LLfIs%1^~Fmxm}z!MlpXM!ieauf|>UFCzuwz!im0^R= z*5}!1C&Bz9`uZyJPiyuIK|05EAH>O&SD5LxDC+Nnnw&TOukrH17`@BYxx3XEJnK%J z{gvN#cljF6ctfRF24A&T`5Nez*ifD= zsbjAR_^M@NR?ctK@+@y_$2x(1n9OOd_f<9_Nf#DUo}!MKFk(5hBjK!gJ&c=&%Wi$! z^?cUJhH7>@I6g3$lI*6uKX%XPCpWJn3%0+b4l(E~2%3L*i+>I?aSp|JnaXzfJU*;h zIavNS9sGlO9g`F7r^8bBj+0k#**3D#EYOCA<_PywVSJ=pczTT%smVVo#Z*$7G_P05 zF4f4qISji=@nm5xx;-dH?R5CGv^tAE!6`{<(axWml`EIM3}$J{Qt?vLV9hd5nU;pO zgI1g_e+ZO__~ur*J-!i9YV$Y(K0evG68%Bxq#^ohPI3jB%zs^1EfIAHq%@jqq=A7- zwtA^0v7PPjv@VB%#h^7p> z4Hh2f@$uYDRlM{pE|SLK`r&5o`xsgm3-i=`F&-&_VGR__^s>oG=ujyaGT!7u&o>`6YsPpSGjkCfkgoo4rj zKB&__h2cQ~H<3(XJaUbmoDQQ`fViyTG*~oWNX43ZtqMc0g{!qxBT!ukL%;pv$MP3K zVM04lWH(7mxTa)78}pH@8u6iW6y`yB^=NGV2p1U-s5PsYtQL_II(N_t4?qNS_@!X_ z=ew*vh=u($p;MMwcnD|NDU|U%Zp9CACthU{;^jm0-@Jp$MymM)QGZgUU5QxfZ|Xz+ z?3fssXS1VNUI*rAldmoBO~~$T5oRWS$mmp1e6m!izVHBzN$QH z=VmoQ_&A;qd}(m!LH_P5%ZWM-U9#P%cgLCFBOk;EL`{l6(RsF#V!ClbaxkOU_L0CK z;2}WqRp24@`61+|71p_^;CH+@vQaPuboY<LTmHn>rS6IQ9Mp28Be3frl3;~vj%i}fNWJB14+YP|NvDS6pj8^(3fiPp zu-KN`8og`nFq|obB9B)OU4bsN-A$- zhCLx`_EL69`iCDo9^Y)IjY=+S9UBUN&RVBfPV^kOluJWNC*G!*!^LvIVo$N!qD9A5 zIZe%H!)A~qq0X-wLnw+ zJdyKpjC@7d7Bsp;lA|2Ne_f~N|3srFaCg6I;$a}M-D!E>^wf)+;4YXttJ*~ zWCav3^W6M^E}7#UA*%avbUJg9DzU2KL`udgdL#L7ChA&pDizOXFpu>=7J0Jp6N-gc zLVAp85}SzW79!C0F%=OJW`&$*)yBnip%4Yq5&c_TdPKJzS&kxF#d53%v&!duUTf2q z^lo{d<}DX zjLVT{iDy>r3d9`=xR3f2IAR#!HW_@NXhWJ$05K4JJVto6_Xlv z@n=JMxeCg+7e(`xK=eRZ5T=V;l$Ng+yuk!#cHXPGEqryimXWPXscB-;lNw@|QO2Zu z_&N$`+`dV#v7W0|LXgQH*K^}<%(%yGYCc#ocevPARh33$C36}uV-kJaHWr%IzXQ(X zx~#-jz?%BUzv6xp{t9uAO4ZwukLuVVetL1bC3w0PoWc~`(0qACdDD3odFo*r8i_bi z;HV^RABiVHqS>I+x!(k`T~v*q>?V;U1sz*q)?3a_isHmD=rQbBTrodCU zRs8nh=b%7S{+IgnFTlsYaJB4zVJZK{!g$!50N@}1WH10FWCY;BINLb_pdo;`oPiA> zNARB)ji4g{T|*~iXKgI20?4*DFmobgg=P?RG6E2i2)P*9{z8vf0V#iL`I|(?%*6DU zrNhYnmylv&qejTV4q(JEadNN$sJaIB5+)XA=FWs10MacdGb0Ot)+!0WvRD`i+L{5F zPk*^30274%p&Qe&Gjq@b(6a1Ygmf%`T3FdxIavX$GDb!KiI<530HNVzVgc}a{+0mH zPE42y|G}aBMJxZi!~YGH`kxN}uM+?1HsL?x0wA>r8915zt?Yl(du10x=YJ{@mK6D` z_Lt$p4Cs`kh>D%Kq=>A6JplS_3>X9pXODl9l|7sQBk*sWjFO3&1>p1WAfyyDwlg#V zAd=)A0XU$)L?_CB7Xu_JyV(B=K=lu?mO-6Rn*~6=0&sRYSpWm3`xn**z^}0ZkVQ;v z%mA($0G|e+g#my(02CDm7sp?6nl?KVBS4)CFkBq}E(rMO|ECf__&@r8fjfZs|LCy; zD7{=<%>SU_7y)>#|HS^Mj4mNNCn11n{2wDY{%?)`C!K|bg`N=r9%dr^k4gUt{kK8? zZ5}5lfNjjq$i%J-IH*MkAQt_n2qzn0JpP^iUk3btHS`}d{?ohvGFlffcSO_)IoSS- zF3J9v;`1*T`9BeKSXcms{=?7Fji0d%WP}~Q_K3jk5C#LK6cv)7({{eHR_SXt^cWvvj{SpQalPDQdV52ei17Jz`=-5g(&@XyUlJIpmU!JCh z_fl8OIqmR&_?bK!mJwj|AmuEwW^(tw!X}N?mfHP*Dn2Tx|KDrY|Hgy=#~1%PAz;<` z|8ZSWTLAy)uc!TwgVIU-d(AR704yH>cLu=k{*tK)l>pO1#ZJ}M;x96Z@Sh3s-%HA0 z9NGVaxWoz|hXEFX|I>V7W@TgsKp_7!V=lU&oK-~8IeaU&m%Vzf9=5Z7%%8zaQh>&P zM}{oa1fi}UGYl|>1gS5(fV2fo65X7|!g9068cHG;fgOd7V&!bfjl6j zj(_;0)^&wAeDv};^BOblcFcFK-je)We!g6#-Eyu9K?w9KkWeT#FYtFrSl5svP&=rR z9WJ-!Vd_wi@2(n984geyxASDHe~19!A+1^c5BMY_iOF;hd`Z0@_^=$&1iYQTi*ya$ zprdx*YClcKMH5cOMeme>0^k>R((By~UbcI2{(v&70*x9mr1E^`r=+lN0_*EV??sl# z|6s)6%^i7O(f4(E3zlYRZF+o0`ni|tH=l>4%%G*@B^%oY)HMTc@55`fepm*9H?#LX zDmc001unKa@wmYh zQz_g%G2%PVzJf^ide}>Dzr$rO7gT4{7)!5d6%o}Enl!AkoI`_<1wYamKG5iMU9&`@ z>m}C69O<3gLSg}XmGK(Bkq?$5=1SEM6m*iqxvY-F^n6pC;q$}eOeXkwyOWEmyE?4; z(7-eYG@QM`r$ZS(3G6`H+)+kHGQQ*5fo$a>G64^TZN;5{dJ1tFGL(v3#B%gu8<6QU zW=3;@3=_r#iVYUHC&CUY|Lo%L#cVSQe8cB2mp6;9-Fs0b2Z0tM}m5cZ&%EWPnM6OCL!GA z^QX+HM?QnsQ3AKaMz{~l9gng$kUN5@0zRFO5?P88$>jV@l;;NQ<%#$vYkCIQ&@t*J zq;A3|&P@LU$CH3)P3MBj<8dUR%g3B$7(W>4A?VIPcXqlJ&Ov`1`s2~BM}Go7Gm*cm z5_5~%yE?uG8#?w59J`pS5~+#k3%nc~fB#J=IRYX}Yrv-_pqq#eM>nr!K2Q4xw%YkU zcNHvwm)K1dQbf++_e+9a%xAYWQ<|xa$NQSDx2{#!s-J}SK0|N3Up3A(&NZzweQ5g7 zyx($%wZ>Yb-fZu0-+9`7%zi8Mx^6$r>Hl5-yMFqGvgVbx zbLW#D0-^t*^B{Ru3C6~e3d z)C!yr^Kd2~g|qq%MNpreBePjBT^aJoa*e3iLN4ya&nJIYh zNq;W=J^dD19~0qLxE&6VTl7z&^>Z%TNZW+FasIzUXcS3$din&`AOe?Q9YoYFd&n-D zz_(9>kBEm{E)2rA+@DURcVn&q+IBPG4%kk5k)bpqO-v6@??EfJ1n044ETaXs;@t+n zhyBDP9Zf%wK8n_DG0x!2kRN{`yM&JRfUv!{RH-WNh`X(4xBm9)+)nom7$09X`n7>)9<9BY3oYS>nklfCdJ z-Ur}4A`v68;2kCrGLBq^_m$)Zav#}99wx0=%0BWQ`GkByz9ipLG%cu1{WL=J@Q%{? z^b-0TdKcY`_dfa={YG#Lc|t!kJ4M(I)M z8R@8OQm)d0?&XvBw->d)(*Yf;JJxlybhM`5MLWfdG8KRjuKq@&jX4?Z>?Jr~{0`;( zRboQk`OtdlPtHcpOd_+$JhB8ic@4RP{EpZC39kC@%|N^ zM(5GB^cLDmU#BMoMKB6h!6_68Lxo0Rny^quULG*Nm<`am|w7s)H-Hu+ylZ>7I7N*S#*DmN)xmDhAlD4oy3lkim6 zaZe5k%Y{1ONw|@gi(dK{`WKYvNibCyPEk_nMzWe-L0W0Pv_$Sp`;rlGRE#69pQG#P zaoSfHPKJ>&FpKuo-X=T5N6@PgpM}HX4s6?B@XbqP6S+}>2M>Ilgr^Fco0WLp>(laBs<9qbf&n5=8#sP z;=^ptCiz5=9B>V36z-6Z&^K`~JHlgF`@QrDVYqlyI)}`_5pV^pgn8-ZuvDrS zUm?>$Ambq>9z^YSxlkrX&|ijHWg_adtvI^3qaGL_496G`O3v9R7voSv+=2IPs3$~} zpqV(v&qXcv7ig8o(l(ebSqN$!v4g zQ%a0S&p4xmg`<-(Vse*=rc@ZChMb-!6>j3$!l&mdloW^S zqT$q@!O?IVnJ~H@=^F+|8^Wo>oF2~UwVXC19f{xr;X2QZ!Qm8X3fHBEES|BZu4yp7 zZnM!aC^~4Gp`;i#8;nRAkxIFvb2k%rf5HjsuIsZISBz$?RLU0}T$l1j2eTTagjn6= zsi{$;>+1&lBaw!Z;uIM)C3=1eq61Ub1kVD4crht?P)gy&glDqWz;)rx#kr=wy23CeGf#nWPxi3BBITgg0+XvOJ>YC~o*3@}shFNgUnpNS{hSBw1 zQzHx;8t@(XER79mS~CQTz8;x4Y)lwSqbnNfQ)C4e8D=eEtZ91EDhAW4V9k^&%!XG3 z!KYGFu}5a6^n;q#sC`&Gdp;$_)M$9kmw*xwJ^b0}F_SYfa!maa7|GM&T%ZIIh)e?cvBQ5xs|W#oGD$r^Pg39<YfGb9=wvZiUx$4sc-rUHalkF9T^gbr#N*swVt)9SZ{0g^nHvRD?$0$~<_ zVFVl5LUla9e_IlunWu_8f`_NH5#VvUY#f0pZB&a>vvCyTL@h4K%B5W^|j-?L@Z^oeY4;Qp4!xpj(gbAWIQ)g+NOE4Ho!pB^a$7? zL_ep8wG?`Ii^W#9e!yAuJ=lb9Cpv+?hxfbmU06mBGM*#WqFaw{C%V1pj-Zq2LA(#( z{SJKxtn_UtMOTY%61w&1cA`6iPN8ojs`M?UpExqQ79FK;A*%Er*sOmbTIqhI_S5}X zwO3mztIM`=B2k(lLa_|t_GbvYtE`Q_((+9qN>m(s8YSv!ArJaPxscZq>ltbjJS{ad zLv8f^E#X9H!+;+2HAtbOSd-VV(GpDExHZpQs_|15LI+x z`XaiQ(Y+2m&?V80LZ_qqTCkWly0;}hFf_o02K@85m=4iB^v~RXnLfw;m*}6k{{s3! z^k1aUwFE;jz=-L9$D=$B%;ME|%Y-yTX2u+g2!yAWb2x>|H2(M>{k6FQmhqD1c!G@jm^KLRcSOAE(Lqy4x|xAb#U5NHK_C zb3IZF;+HN*ib4Fs#Yi!TPo0GngZP9=NHK_y9E%h}8@=bL{DM&B$k`-3z)CMcE?t6L zx&*m&35d8p#2da5S>5hzDJnva-H}Wb7KNI(lja?y`5e-GA8DROny)0y%Sm$$Y5o;y zPLSpRX%3R+Bx!z{R3R&xNwW2{V0F?%nqMT%kCWyFq&ZHSW28BsG>1uLvW-Ss&MfC% z9rv~jV1o|*e*IDVSZM?~8bO(lpibC{xEEcThmx2noTp{>2AQ9?rKna5ckfd+XTTZs zS$yzW?1pFI06Gyn=vfq_XYnP^vMqYVT6B}p?Lv11T^gN?x%05%H*vHgmZGagHwoP` zbVtz1ygEnFQJ9md;wE0P(oCgCvJib1Z?*uB&`2^@4X6qA4B@5#u?ES=U^+-E!R12p zz;4so+K74USLUz3GJ}4Ap591rf?Vu~wHg1WmTz)HZREC=_|u^QPV!p_iYRrY8sa2| zeiba>;a(8XF~0%=^ilN7S_0$oF>6b_IJBKu*i&0W-vkbYJ_)o@BtH&39eN|&CX$xW z-!SIUt)bTf*M?pwZPQ`Qj(8hEZ+n<$-4>_{J^mukx*QYkXbD}(yse=t0z*Ty13Y1x zmhh_u7)n}0=fo$3&cOE#4xArKF2Hwg4b=vI6{^v4^ZlHMj<)o{WP*KH za>)E6GTRC!AaYuzz&}&*PfwKSC@$$zIl?eHY|KD1EVXM23_CxZIzA@aMhs}JNYQ~L zWgiB^#tuwXC5E*r>2p$*iD4;a)Oq!r3AwQWV^efB&eCJ++en&4t?;vT!8Rbow&Dgq z^SiCMp`ighuEn*UT6=$6^^n2e15FuBoVq-x(YdL0!^YI79?5M;l`$fn+b}HkYqoIM zM!q0N>jrNl|6*Q4{WhUL`J(O|7BBQ4+|V$rjg05{AWZ&+`A}m1#q;TKVrKautP5)S z?$GkZ@OjLa&pgbh*F%iwi|O?|pGa7~%?tAD25-*K=Xu;=SitivaEH6*c`=50Vlke_ z)eJB4JTJPMS)NpXo+S{#EWrTJLVOV5Spvkzvy4BLr8JY}+RiN3@{$B{Do;SmV?LP8 zV?Ky^5i3AdD$rTvIg+#a7?iz3tL%dk~~-Tjrg~d zjhQ4BqixZFkXX2A!6NX~%^a-#TYwivEnLJHu3=)q4_%m6hl}LF3l;(lOBIb7ma0W- zcC(^jY!hozs!uk~XskoqUW@FGk$qUCAarJAaWyPXug_%sZvQXJ_=DIeXr@nZA;}imG62W(l($Z7DWAENH+6E+7fAAp4F?wG#=@!ob>`bqg0|s0=R_W_;~Q zd}KkEC7l;zR-%(*3-N{Q5= z3ev}+7`h>raO@66h^3G~>;WZ+JrTczGU$$24yA|{&?9{edU5OxJrOIR9I*;2(*K5P zj(wmPVqcCm&>OKIR3i3=D#Ti-PJaPO=z}-_`XUa58pJ_}|AN8L53vsVBMyPu^idcJ zNyIZ?0OFZ25b-RI!(b5N*)SM!I1EW2fe{=>!cfFfa0cRNI5Yh@oWpSpoP{_RhNTa~ zI2evNp5wVN0=^3=0sK!$QQXU{RXwV=qR$hT{sjB>f(&ge8cpU@78ixD@ePxGeoHtbxlB zuY)Tv=6b|;;Rd)8@kUsNcoQr~T#I-RZicH6Z-J{3e+}2955R9Y-U=%a*TE{p-@uOQ?|~Z;*TYSS8(=Nsy@+qaeQ-14{csE71Mq9a z-@$LvZ^46bYx*DX5UfMo2){*qnByaG8{(sIJK|$-C*tEApMbj%H^JSADYyr5Gva<| zf%S-6U;|<++?Re6o`n0;e}}CcpMnPv+u(PI+u%XO?Hr$mjfgwo;q)8udw2x#4;**G zqlmlUF~mQ@gWA`o}+@(?9x-PXF*H==4LKI(`0WI{p10(CP1Uo&NrJ zbozT-r@z-lr@zN_`g>fbzt=^lzxy4Xevs?*gIuQ{{4dn$Z~ja={k8w;^#AGf|2m!i z-)^V>_v-W?veW;k)BmT_zh9^S`Tqf(4(u!_95Whpoxcg9qKLGJAz79Y@Xn;@K*2ar zC@6?Jbm(U{c7W%XWl@$XNL0rj7G*(}4g58~v`Yk&QU5({RuqN(_D0F3C^*^a5Co2T z9q7^Lm)2%vfuacb4`ji}9u_eq=_N_}S(^2umk4H~0kmJZWZEn;=xlQ)MbB;>YqK8P zY`}nC$-aSQQP{=XtYq6PVw?GEercBoRwHdQNoZ;r(*)GJJn_*U`q`G;7~A_ z3}7_qvu|KobnFs!I@V@0dsxDdg00v6EY14SO9Itw`kprH^?I#yGbu(i+fX2k0^m?E zn$VInp4Mg*cfDTJ>qO9DoAKdnn}31*EP>5zW*)x;rg9`%>eA*+O190?ciJrREP8fH z*lgBj_OPrI_1I?pFR-6w$WbkwZ5BJ*Y&05KLyg%KGc(CeV3u+GgV~BfbLMxPTAK|< zgV87(4I=186-kf{l0nZ~|BJh1aH=Zv_$4w?l-Vp~GMU(~Q%%_vGh2XQOJ%T_z=CYD zT1?qDuq-BIl1VnA92i8E$$^3#Fj@`9UtpUR@Hp(u)( z8OJ}^a#XM}@zCDDvY0IC}EhoJsM5AG~hx>jC@NpNl~Z z@yo!oIGj07hr!8YUkR~?O?HFR=C@(%e{q)yit@vqe=|X6!Qp3Ovyj`3O>*O%NeQqm zEgu9;5O6~~!fow{IZA*qA-vZdj`2`rn5Wg%uOCaD41T2Ao3B0Cm z>|vYN67WVnUhmJ+tRKB>(7U9NHJx7urn#&*14A$vM8G?fk`D#gOenBIeh>sw1gSlq#n@e)>VY}a&>o4&6eLqXHe)O_KpPt2RCgzusO}c6hJ3=20v%eh@ z&ZZPV5fntB$O;8vC@R5VLB5uv@+{$SZaA!l!)6GYd$Nafa@BBdVZa~wIa>AOR}KuS zE@K|Q%20LD#-kW8?dn9=fv3vii(O5@Xn-^L2oGQ4!xaFRs_BKV6d!2 zOL6inMMd$VB4<&N4dS+1_OLhZEQun%Pq2a4R?3;Pxo`~v@;K>#KW zuVb?kzw9AY#y*^lpuD^s0q;yoKNtx8s$ifG`jx}LGcedM^LH?OJWF|b_wsUoMY#h? z9mCnfq3*u&k^vi~tO( zf-^>7a8Q3OCBU;(Rh3m$a|*)pFj-3|nI+GA$dgcy zHy(!C!^CEz zJ*$CXy+F`!h4sR(EN$tdt*T1LA@Oyq)yj!Ot!6VPK1*5+20G4a30bJ+F?*(t?1<-o z)H5dvwu*u{-sLX0%c;`#sN5;@*NX~@9h{(4w83wY+JWx!Ykjl@Bh5xiw^de zlOE}Khg=PN(6k@%qyf9;QMrwbO2&y$Ln$$k8Zb}+10Yu^eMZ70m;=jT1NO`Y5Y@wKJMWa9J<7359I{f-yLaW*J)_PotL`oA*)#9D_;By!^RV0j zq>av^7ojv1C%tp&T!9WJ!?DOHP@goH{rNI+?hT&A2=!2-`XQ7KKisni%)>_ZiZ}<* zLelo+lT1>!^S^qt2j3D)dMK-GjaJ1?Aa20)4I;1Q@kTB!TBWw{*|Uc|djN&4OH4bYa} zl{7@66+M8k{%=bkluLd^qBdDpdSNG& z({Eb`ygK%`@0BhTFYAAK=!u~(PQqH&usuBFLXdj4fs+2Xm2p7F1d%mgX~P&s@EFDf zj5)T25u0W9L&2oprkXuDIr2C&CbZgYocKJcS5>5f4k?IlNV-{uV34H-0~SmPnpkUt zZS?7+i5lGQa7eXL8V;f4l)koy;T|YG%o<)@YBbuR>zGffSq zv6k7Usg_Iam*!k+-(mm2_ksVY&$QF{R1Wp40X0_*s`4MwN0EyML5IE`d)OB=s5)7G zG2n9q0zO^9ClIRh1q5?YZKDrt8EGT7HsX1bwE$R^w-9PFFivtoY)gN^xsSxxNtJQk zu)zH)3U3lcgFH=_Gn1E8B~7*`Yw099hc2Tc-A?l%L~h!A9T)s#s3Q_J>M_PfR2A(t zwTIgq583QYRuEQMx+g4GsJpc>%O;^J!T=gcj-ckf;m@n{|&)8%C@ z9Nnl7Wkpm@R#JED{yUCry#2DP?jqZAzW(d0$Ip1^nfoRNAAfv6&6HhN?*8C{*}uMP zP0rpoKYhIZksS}Lp4^j-!13u1MHk9mg0yZGJgmi1TSfvIp^2H+>qf69$vV#y0K&#b z!h``*7&Vx!CTq}OD0Bt`Vz4kE6`G@FlgEpCHmtJI7FOc?otQmdn%Kksu^a5wwY8|N z4rAvZeolSPUajs*#!Px)W1OOAJADAWbVgE-wUn@$W_z}a?b$B2 zvo3b97TXt03eO4Cu!jwiaI=!ls${b&omrIyaV7~p;soMqoMKClJ;k1iuPyPkk*XH& zt7JPtvjQ1r#C&03zxrKU+(vH6NJru@mk(4SOg@e!8Z|LFj6!mVjSE!gOjtBoLCu2F zfy#x1o zb$t0D`-_vq(;taWl$u;9qQW+?+S)w4T#iCppF)HHWoaAURF<$cA zjF6dLF>v;(rc)9avXT&)Lkl<4fu32C&*{ZAfG3Le1;6Rk?Le# zt$UJtj(eF~bgL}M&AI4yv1i>bR#SHy&EJxEo{J!#!I;!_mBYiD2y)RwHgUnLs$yB0 z_%)DIKXU<$Qqbl>2}D)IuJnJhT0t&q(nbdD1t-)Ummo&1eXK2DsOanc3$WQR-QFf;Z2n%(gfuZWzjh^$rQP%AU2 z7{TK*<+C^>PA2nMBrBFZ>EtGelehF#`?7^$S)?>mfvjUgwX&Cs6uQoIof-eo^hpm% z--BEMSCGrag}Qmh`KCqYOWoJO8gjk3Qn%cAjcKL%2KURh=W^_MI3!yFVIT9t;Zo+6 zgyU?SdJDrQ2ztPT)!5LTbm4S%Xa=)GGsuP}S4_bLJM~1rolb{DCQ~AtDbYE86AP@# zFpghb`B+sewYHI)lio59AG97mXgz$;dKRS6!f&I~lg@men9mdQd1C$oXVw%AJCjc8 zT-)>c?9{sq( z$I)dRcOBGZ*4zs}+_~%1*%z(4q2u_QZ+0BN`TUi$XRNsPg6XUKoVj+)@{NyQwd^6m zUwGTB4f_vlxZt;i#k*JUNCP3eZu%n`JL8(GCrw#(&B^rewId&FzUq;UY>wH6=E+Ji z&ey6{$*?Gatmvs+BMLP{7IBqP3bjC)m4B};vksbvN~;zP3f^LERmv8n=(gd4LulBu z=j21U@SyB(XG#sYx>dkJbGHFO!#ZQ^o#ceREfXVU36b@wn@?#vhO)@Di!PJtgr**J zGDDG#FCL~QhJ=L&FiJM?DbK|hH$2TK^MVchJskBG{(ep?oF*144qwW|D?@zEXCKPm z+rWn)A5Id-QniOVT{lDDq^=g$sxL^-$-C5}s!=C3knwbsI>VS!|84rW`QH}3XcEn$ zMKBulk|?49rIQuKgtSgJDFlGE*veN+Va4RYBq|6j&dK70uxN7NQ~IDJ>4LH#x6!#t zJ?KoIBq^bEJ27JC8k2TY7^W%0IitkA;sH@uD-yAdkfd>xX_s=qB&;YhlT*}ST|hx@$KZPnGQ z)ZM!+yLYdWG#>?jSjsqNSSmPrLVc@f6?DpWTo^$5Yc>`d$ozSYKR6EXijr~?6(T}T zM2Hv2ia^W%O6%W#wEfO|-z5LKeMnxQT-ttO2-(pwm`)(;wq0_=b1ApMcFSb7!h zqa#mFp|f%+(G;`H)|?+FCow7vW#%a`7Z&C=!!@~U;ST9h;dkb3LaX_C^FBC~`|n(v z#hz=+%@vB|ZnmO8I5gBe-f^yTymy8)JNGjCb@n@i+bwqlHj)SEM%&*kIp6@F>QH?m z%Edb^-Kx2fUe~Q!wE_|SXetQ)pr}{l*0UfUCWQDxZpy^V&2^32z)ggBSVvH(nK5Q! zwbXfoQzo(n?=iFyhBMVN0u|5j!x{U)#!XU8YMh4)-UOLX+_D(W%cs36?D^$oqFaeG z{Xm@#JJS|o>ofg2p8eo(#~XKUB7>fJixl_WS^mtgAAW!0MIWxb|2;~39{Ki<UT)hw1$?UIm8lg4ml%=3frzjwZK@>QHK4=7;!dhIa z+AEZ?!dYQM*h~#Rv#6)quwt#$^H%D^e0Lz6*%~;`XGKnAwgpbKa=B-OUf&rbYdZ!8 zzDv+(>U&;>FWMGB&G2^gYB+n29m*{9(BVv0qqf)d>``uuI3pQ%pO}C09wBk^Z^AXw z_QyMFAL}qbjx|EXC$7L2>fyd*KisZpnsbXq;Q@&843pW}E^&qXk-D7X~(oVNstFPIgD6u0VSHgy-VrpSb~ zLvC!wB>^>Zz8E=QjGQmVaAq%PSJHr0_z4WsWf=5TmO)=9U71b~n@JdL`X=*Sv)H%6 zgXVJQCJ?fVb4zX1VvtJ=`Q{+b#5Ig(BvEcdzM+dEKJW}Z@ys*rvb4SZK|0~Y5W1y( zIM#G0vTr$ZP9S+nFXinKI8ueRN>DPB$~T-{SiNsF8`|fE0+O zxTYNi2jD13_Ao}S1%YShoduo@yFbga`|~Wjk0(`adg1K8Pkg<>)48SAIA~&hOEb

{iCUgGN_)icr3+anc1m;tKOEv9Nai`{}@ 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 literal 0 HcmV?d00001 From f0f6e4491ceb47e8cc4e6816330aa796ed37f519 Mon Sep 17 00:00:00 2001 From: taisirhassan Date: Wed, 14 May 2025 18:32:17 -0400 Subject: [PATCH 2/9] Add Peripheral Pin Select (PPS) configuration for PIC18F26K83 This commit introduces the pin_config.h and pin_config.c files, implementing the initialization and configuration of PPS mappings for I2C, SPI, and UART peripherals. The pin_init function is added to set up all necessary pin configurations after MCU initialization. Additionally, helper functions for unlocking and locking PPS registers are included to ensure safe modifications. --- include/pin_config.h | 19 +++ pic18f26k83/pin_config.c | 267 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 286 insertions(+) create mode 100644 include/pin_config.h create mode 100644 pic18f26k83/pin_config.c diff --git a/include/pin_config.h b/include/pin_config.h new file mode 100644 index 0000000..6cb651e --- /dev/null +++ b/include/pin_config.h @@ -0,0 +1,19 @@ +#ifndef ROCKETLIB_PIN_CONFIG_H +#define ROCKETLIB_PIN_CONFIG_H + +#include "common.h" + +/** + * @brief Initializes the Peripheral Pin Select (PPS) configuration + * + * This function sets up all PPS mappings for peripherals including I2C, SPI, UART, and Timer + * inputs. Note that PWM/CCP PPS configuration is handled by the PWM module itself when pwm_init() + * is called. + * + * Should be called after basic MCU initialization (mcu_init) but before peripheral initialization. + * + * @return w_status_t W_SUCCESS if successful + */ +w_status_t pin_init(void); + +#endif /* ROCKETLIB_PIN_CONFIG_H */ \ No newline at end of file diff --git a/pic18f26k83/pin_config.c b/pic18f26k83/pin_config.c new file mode 100644 index 0000000..12ae27d --- /dev/null +++ b/pic18f26k83/pin_config.c @@ -0,0 +1,267 @@ +#include "pin_config.h" +#include "common.h" +#include + +/** + * @brief Unlocks the PPS registers for configuration + * + * Implements the specific sequence from the PIC18F26K83 datasheet + * to unlock the PPS registers for modification. + * + * @return w_status_t W_SUCCESS if successful + */ +static w_status_t pps_unlock(void) { + INTCON0bits.GIE = 0; // Disable global interrupts during critical sequence + PPSLOCK = 0x55; // First unlock sequence value + PPSLOCK = 0xAA; // Second unlock sequence value + PPSLOCKbits.PPSLOCKED = 0; // Clear PPSLOCKED bit to enable PPS changes + INTCON0bits.GIE = 1; // Re-enable global interrupts + + return W_SUCCESS; +} + +/** + * @brief Locks the PPS registers to prevent accidental changes + * + * Implements the specific sequence from the PIC18F26K83 datasheet + * to lock the PPS registers after configuration is complete. + * + * @return w_status_t W_SUCCESS if successful + */ +static w_status_t pps_lock(void) { + INTCON0bits.GIE = 0; // Disable global interrupts during critical sequence + PPSLOCK = 0x55; // First lock sequence value + PPSLOCK = 0xAA; // Second lock sequence value + PPSLOCKbits.PPSLOCKED = 1; // Set PPSLOCKED bit to lock PPS registers + INTCON0bits.GIE = 1; // Re-enable global interrupts + + return W_SUCCESS; +} + +/** + * @brief Helper function for PPS input mapping + * + * Sets up the mapping between a peripheral input and a physical pin. + * + * @param pps_register Pointer to the peripheral's PPS register + * @param port_pin_code Code representing the port and pin (format: 0bPPPNNN where PPP=port, + * NNN=pin) + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if pointer is NULL + */ +static w_status_t pps_input(volatile unsigned char *pps_register, unsigned char port_pin_code) { + if (pps_register == NULL) { + return W_INVALID_PARAM; + } + + *pps_register = port_pin_code; + return W_SUCCESS; +} + +/** + * @brief Helper function for PPS output mapping + * + * Sets up the mapping between a peripheral output and a physical pin. + * + * @param rxy_pps_register Pointer to the pin's PPS register + * @param peripheral_code Code representing the peripheral output function + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if pointer is NULL + */ +static w_status_t +pps_output(volatile unsigned char *rxy_pps_register, unsigned char peripheral_code) { + if (rxy_pps_register == NULL) { + return W_INVALID_PARAM; + } + + *rxy_pps_register = peripheral_code; + return W_SUCCESS; +} + +/** + * @brief Configures I2C1 pins for RC3 (SCL) and RC4 (SDA) + * + * Sets up PPS registers for the I2C1 module on the PIC18F26K83. + * Configures both input and output mappings since I2C is bidirectional. + * Also configures pins for digital mode and open-drain operation. + * + * @return w_status_t W_SUCCESS if successful + */ +static w_status_t pps_configure_i2c1(void) { + // Configure digital mode for I2C pins + ANSELCbits.ANSC3 = 0; // Set RC3 to digital mode + ANSELCbits.ANSC4 = 0; // Set RC4 to digital mode + + // Set pins as inputs initially (I2C peripheral will control them) + TRISCbits.TRISC3 = 1; // Set SCL as input + TRISCbits.TRISC4 = 1; // Set SDA as input + + // Input mapping for I2C (from pins to peripheral) + I2C1SCLPPS = 0b010011; // Map RC3 to I2C1 SCL input + I2C1SDAPPS = 0b010100; // Map RC4 to I2C1 SDA input + + // Output mapping for I2C (from peripheral to pins) + RC3PPS = 0b100001; // Map I2C1 SCL output to RC3 + RC4PPS = 0b100010; // Map I2C1 SDA output to RC4 + + // Enable open-drain mode for I2C pins (required for I2C operation) + ODCONCbits.ODCC3 = 1; // Set RC3 to open-drain mode + ODCONCbits.ODCC4 = 1; // Set RC4 to open-drain mode + + return W_SUCCESS; +} + +/** + * @brief Configures SPI1 pins for master mode + * + * Sets up PPS registers for the SPI1 module in master mode: + * - RB1 (SCK) - Clock output + * - RB2 (SDI) - Data input + * - RB3 (SDO) - Data output + * + * Also configures pin directions and digital mode appropriately. + * + * @return w_status_t W_SUCCESS if successful + */ +static w_status_t pps_configure_spi1(void) { + // Configure digital mode for SPI pins + ANSELBbits.ANSELB1 = 0; // Set RB1 to digital mode + ANSELBbits.ANSELB2 = 0; // Set RB2 to digital mode + ANSELBbits.ANSELB3 = 0; // Set RB3 to digital mode + + // Set correct pin directions for SPI master mode + TRISBbits.TRISB1 = 0; // SCK as output (master mode) + TRISBbits.TRISB2 = 1; // SDI as input (master reads data) + TRISBbits.TRISB3 = 0; // SDO as output (master sends data) + + // Input mapping for SPI (from pins to peripheral) + SPI1SCKPPS = 0b001001; // Map RB1 to SPI1 SCK input (for slave mode or feedback) + SPI1SDIPPS = 0b001010; // Map RB2 to SPI1 SDI input + + // Output mapping for SPI (from peripheral to pins) + RB1PPS = 0b011110; // Map SPI1 SCK output to RB1 + RB3PPS = 0b011111; // Map SPI1 SDO output to RB3 + + return W_SUCCESS; +} + +/** + * @brief Configures UART1 pins for communication + * + * Sets up PPS registers for the UART1 module: + * - RC6 (TX) - Transmit output + * - RC7 (RX) - Receive input + * + * Also configures pin directions and digital mode appropriately. + * + * @return w_status_t W_SUCCESS if successful + */ +static w_status_t pps_configure_uart1(void) { + // Configure digital mode for UART pins + ANSELCbits.ANSC6 = 0; // Set RC6 to digital mode + ANSELCbits.ANSC7 = 0; // Set RC7 to digital mode + + // Set correct pin directions for UART + TRISCbits.TRISC6 = 0; // TX as output + TRISCbits.TRISC7 = 1; // RX as input + + // Input mapping for UART (from pin to peripheral) + U1RXPPS = 0b010111; // Map RC7 to UART1 RX input + + // Output mapping for UART (from peripheral to pin) + RC6PPS = 0b010011; // Map UART1 TX output to RC6 + + return W_SUCCESS; +} + +/** + * @brief Configures timer external clock inputs + * + * Maps a physical pin to serve as the external clock input for a timer. + * Also configures the pin as a digital input. + * + * @param timer Timer number to configure (0, 1, 3, 5) + * @param port Port number where clock input is located (0=PORTA, 1=PORTB, 2=PORTC) + * @param pin Pin number within the port (0-7) + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if parameters are invalid + */ +static w_status_t +pps_configure_timer_clk(unsigned char timer, unsigned char port, unsigned char pin) { + // Create the port-pin PPS input code (format: 0bPPPPPP where bits 5-3=port, bits 2-0=pin) + unsigned char port_pin_code = (port << 3) | pin; + + // Configure the pin for digital input + switch (port) { + case 0: // PORTA + if (pin < 8) { + ANSELA &= ~(1 << pin); // Set pin to digital mode + TRISA |= (1 << pin); // Set pin as input + } + break; + case 1: // PORTB + if (pin < 8) { + ANSELB &= ~(1 << pin); // Set pin to digital mode + TRISB |= (1 << pin); // Set pin as input + } + break; + case 2: // PORTC + if (pin < 8) { + ANSELC &= ~(1 << pin); // Set pin to digital mode + TRISC |= (1 << pin); // Set pin as input + } + break; + default: + return; // Invalid port + } + + // Map the pin to the appropriate timer input + switch (timer) { + case 0: + T0CKIPPS = port_pin_code; // Timer0 external clock input + break; + case 1: + T1CKIPPS = port_pin_code; // Timer1 external clock input + break; + case 3: + T3CKIPPS = port_pin_code; // Timer3 external clock input + break; + case 5: + T5CKIPPS = port_pin_code; // Timer5 external clock input + break; + default: + return W_INVALID_PARAM; // Invalid timer + } + + return W_SUCCESS; +} + +/** + * @brief Initializes all PPS configurations for peripherals + * + * This function sets up all Peripheral Pin Select (PPS) mappings + * for the PIC18F26K83 microcontroller. It configures: + * - I2C1 pins (RC3/RC4) + * - SPI1 pins (RB1/RB2/RB3) + * - UART1 pins (RC6/RC7) + * + * Note that PWM/CCP PPS configuration is handled by the PWM module itself. + * This function should be called after basic MCU initialization but before + * initializing any peripherals. + * + * @return w_status_t W_SUCCESS if successful + */ +w_status_t pin_init(void) { + // Unlock PPS registers before making any changes + pps_unlock(); + + // Configure all required peripheral pins + pps_configure_i2c1(); + pps_configure_spi1(); + pps_configure_uart1(); + + // Note: PWM/CCP PPS configuration is handled by the PWM module (pwm.c) + // When pwm_init() is called, it will configure the necessary PPS settings + + // Lock PPS registers after all configurations + pps_lock(); + + return W_SUCCESS; +} \ No newline at end of file From c7a730b79c838c4b4a9c8185695c9ffe4005212e Mon Sep 17 00:00:00 2001 From: taisirhassan Date: Wed, 14 May 2025 18:32:35 -0400 Subject: [PATCH 3/9] Add pin_config.rst documentation for Peripheral Pin Select (PPS) configuration This commit introduces a new documentation file, pin_config.rst, detailing the setup and usage of the PPS module for the PIC18F26K83. It includes an overview, function descriptions, implementation details, and usage examples for initializing and configuring peripheral mappings for I2C, SPI, and UART. The index.rst file is also updated to include this new documentation. --- doc/index.rst | 1 + doc/pin_config.rst | 154 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 doc/pin_config.rst diff --git a/doc/index.rst b/doc/index.rst index 7c9eddd..81ef506 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -8,6 +8,7 @@ The standard embedded firmware library is a common library for Waterloo Rocketry :caption: Contents pic18_init.rst + pin_config.rst i2c_driver.rst gpio_driver.rst spi_driver.rst diff --git a/doc/pin_config.rst b/doc/pin_config.rst new file mode 100644 index 0000000..ccfe487 --- /dev/null +++ b/doc/pin_config.rst @@ -0,0 +1,154 @@ +Peripheral Pin Select (PPS) Configuration +************************************** + +Overview +======== + +The Peripheral Pin Select (PPS) module allows connecting peripheral inputs and outputs to +different physical I/O pins on the PIC18F26K83. This module provides a clean interface +for setting up all the necessary PPS configurations at initialization time. + +Functions +======== + +.. c:function:: w_status_t pin_init(void) + + :returns: Status code indicating success or failure + :retval: ``W_SUCCESS`` if PPS initialization was successful + + Initialize Peripheral Pin Select (PPS) configurations for all peripherals. + + This function configures the appropriate PPS settings for: + + * I2C1 (SCL on RC3, SDA on RC4) + * SPI1 in master mode (SCK on RB1, SDI on RB2, SDO on RB3) + * UART1 (TX on RC6, RX on RC7) + + Note that PWM/CCP PPS configuration is handled by the PWM module itself when :c:func:`pwm_init` is called. + + This function should be called after basic MCU initialization but before any peripheral initialization. + +Implementation Details +===================== + +Helper Functions +-------------- + +The implementation includes several helper functions for managing PPS configuration: + +.. c:function:: static w_status_t pps_unlock(void) + + :returns: Status code indicating success or failure + :retval: ``W_SUCCESS`` if unlock operation was successful + + Internal function that unlocks the PPS registers for configuration. Per the + PIC18F26K83 datasheet, modifying PPS registers requires a specific unlock sequence. + +.. c:function:: static w_status_t pps_lock(void) + + :returns: Status code indicating success or failure + :retval: ``W_SUCCESS`` if lock operation was successful + + Internal function that locks the PPS registers after configuration to prevent + accidental changes. + +.. c:function:: static w_status_t pps_input(volatile unsigned char* pps_register, unsigned char port_pin_code) + + :param pps_register: Pointer to the peripheral's PPS register + :param port_pin_code: Code representing the port and pin (format: 0bPPPNNN where PPP=port, NNN=pin) + :returns: Status code indicating success or failure + :retval: ``W_SUCCESS`` if mapping was successful + :retval: ``W_INVALID_PARAM`` if pps_register is NULL + + Helper function for configuring peripheral input pin mappings. + +.. c:function:: static w_status_t pps_output(volatile unsigned char* rxy_pps_register, unsigned char peripheral_code) + + :param rxy_pps_register: Pointer to the pin's PPS register + :param peripheral_code: Code representing the peripheral output function + :returns: Status code indicating success or failure + :retval: ``W_SUCCESS`` if mapping was successful + :retval: ``W_INVALID_PARAM`` if rxy_pps_register is NULL + + Helper function for configuring peripheral output pin mappings. + +Peripheral Configuration Functions +---------------------------- + +.. c:function:: static w_status_t pps_configure_i2c1(void) + + :returns: Status code indicating success or failure + :retval: ``W_SUCCESS`` if configuration was successful + + Configures I2C1 to use RC3 for SCL and RC4 for SDA. Since I2C is bidirectional, + both input and output mappings are configured for each pin. The pins are also set to + open-drain mode as required for I2C operation. + +.. c:function:: static w_status_t pps_configure_spi1(void) + + :returns: Status code indicating success or failure + :retval: ``W_SUCCESS`` if configuration was successful + + Configures the SPI1 module in master mode using: + + * RB1 for SCK (output) + * RB2 for SDI (input) + * RB3 for SDO (output) + +.. c:function:: static w_status_t pps_configure_uart1(void) + + :returns: Status code indicating success or failure + :retval: ``W_SUCCESS`` if configuration was successful + + Configures the UART1 module using: + + * RC6 for TX (output) + * RC7 for RX (input) + +.. c:function:: static w_status_t pps_configure_timer_clk(unsigned char timer, unsigned char port, unsigned char pin) + + :param timer: Timer number to configure (0, 1, 3, 5) + :param port: Port number where clock input is located (0=PORTA, 1=PORTB, 2=PORTC) + :param pin: Pin number within the port (0-7) + :returns: Status code indicating success or failure + :retval: ``W_SUCCESS`` if configuration was successful + :retval: ``W_INVALID_PARAM`` if timer, port, or pin parameters are invalid + + Configures an external clock input for the specified timer. This is not called by default + in the initialization routine but is available for applications that need external timer + clock sources. + +Usage Example +============ + +The PPS configuration should be performed early in your application's initialization sequence: + +.. code-block:: c + + int main(void) { + // Initialize the microcontroller (clocks, etc.) + mcu_init(); + + // Configure PPS mapping for peripherals + w_status_t status = pin_init(); + if (status != W_SUCCESS) { + // Handle error + } + + // Now initialize peripherals that depend on PPS configuration + i2c_init(frequency_divider); + spi_init(mode, clock_polarity, clock_phase); + // ...other peripheral initializations... + + while(1) { + // Main application loop + } + } + +Notes +===== + +* The actual pin assignments can be modified in the `pin_config.c` file if different pins are required. +* PWM/CCP pin assignments should be configured through the PWM module's own initialization function. +* When switching between peripherals that share the same pins (e.g., SPI and I2C on the same MSSP module), + the PPS configuration must be updated accordingly. \ No newline at end of file From 146aaa59c9dec63129db7668095f1cbd518a56d7 Mon Sep 17 00:00:00 2001 From: taisirhassan Date: Wed, 14 May 2025 18:56:01 -0400 Subject: [PATCH 4/9] fix sphinx warning html when building --- doc/pin_config.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/pin_config.rst b/doc/pin_config.rst index ccfe487..e6349a9 100644 --- a/doc/pin_config.rst +++ b/doc/pin_config.rst @@ -1,5 +1,5 @@ Peripheral Pin Select (PPS) Configuration -************************************** +****************************************** Overview ======== @@ -9,7 +9,7 @@ different physical I/O pins on the PIC18F26K83. This module provides a clean int for setting up all the necessary PPS configurations at initialization time. Functions -======== +========= .. c:function:: w_status_t pin_init(void) @@ -29,10 +29,10 @@ Functions This function should be called after basic MCU initialization but before any peripheral initialization. Implementation Details -===================== +===================================================== Helper Functions --------------- +------------------- The implementation includes several helper functions for managing PPS configuration: @@ -73,7 +73,7 @@ The implementation includes several helper functions for managing PPS configurat Helper function for configuring peripheral output pin mappings. Peripheral Configuration Functions ----------------------------- +------------------------------------------------- .. c:function:: static w_status_t pps_configure_i2c1(void) @@ -119,7 +119,7 @@ Peripheral Configuration Functions clock sources. Usage Example -============ +============= The PPS configuration should be performed early in your application's initialization sequence: From e2fb080d66340d20b63df14bd2ae5c0ded662c6c Mon Sep 17 00:00:00 2001 From: taisirhassan Date: Sat, 31 May 2025 03:26:50 -0400 Subject: [PATCH 5/9] Refactor PWM initialization and duty cycle update functions This commit simplifies the PWM initialization and duty cycle update functions by removing the pin configuration parameter and introducing dedicated functions to retrieve register addresses for CCP modules. --- include/pwm.h | 69 +++++++++------------------- pic18f26k83/pwm.c | 112 +++++++++++++++++++++++++++++----------------- 2 files changed, 92 insertions(+), 89 deletions(-) diff --git a/include/pwm.h b/include/pwm.h index 85ec508..535cc34 100644 --- a/include/pwm.h +++ b/include/pwm.h @@ -4,54 +4,25 @@ #include "common.h" #include -// Structure to hold the configuration details for a PWM pin -typedef struct { - uint8_t port; // Port letter (A, B, C) - uint8_t pin; // Pin number (0-7) - uint8_t pps_reg; // PPS register value for this pin -} pwm_pin_config_t; - -// Macro to concatenate tokens for register naming -// This macro concatenates three tokens together, used for constructing register names dynamically -#define CONCAT(a, b, c) a##b##c - -// Macro to get the CCPR Low register based on module number -// This macro forms the register name for the low byte of the Compare/Capture/PWM register -#define CCPR_L(module) CONCAT(CCPR, module, L) - -// Macro to get the CCPR High register based on module number -// This macro forms the register name for the high byte of the Compare/Capture/PWM register -#define CCPR_H(module) CONCAT(CCPR, module, H) - -// Macro to get the CCPxCON register based on module number -// This macro forms the register name for the control register of the specified CCP module -#define CCP_CON(module) CONCAT(CCP, module, CON) - -// Macro to get the TRIS register based on port letter -// TRIS registers control the direction of pins (input or output) -// This macro dynamically constructs the TRIS register name for a given port -#define GET_TRIS_REG(port) CONCAT(TRIS, port, A) - -// Macro to get the PPS register address based on port and pin -// PPS (Peripheral Pin Select) allows mapping of peripherals to different pins -// This macro forms the PPS register name for a given port and pin -#define GET_PPS_REG(port, pin) CONCAT(R, port, pin##PPS) - -// Macro to set the TRIS register for a specific pin -// This macro configures the specified pin as an output by clearing the corresponding bit in the -// TRIS register -#define SET_TRIS_OUTPUT(port, pin) (GET_TRIS_REG(port) &= ~(1 << (pin))) - -// Macro to assign the CCP module to the PPS register -// This macro assigns the CCP module to a specific pin by writing to the PPS register -#define ASSIGN_PPS(port, pin, ccp_module) (*GET_PPS_REG(port, pin) = (ccp_module)) - -// Function prototypes -w_status_t pwm_init( - uint8_t ccp_module, pwm_pin_config_t pin_config, uint16_t pwm_period -); // Initializes the PWM for a specific CCP module -w_status_t pwm_update_duty_cycle( - uint8_t ccp_module, uint16_t duty_cycle -); // Updates the duty cycle of the specified CCP module +/** + * @brief Initialize PWM for a specific CCP module + * + * This function only handles PWM initialization. Pin configuration must be done + * separately using the pin_config module before calling this function. + * + * @param ccp_module CCP module number (1-5) + * @param pwm_period PWM period value + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if parameters are invalid + */ +w_status_t pwm_init(uint8_t ccp_module, uint16_t pwm_period); + +/** + * @brief Update the duty cycle of a specific CCP module + * + * @param ccp_module CCP module number (1-5) + * @param duty_cycle 10-bit duty cycle value (0-1023) + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if parameters are invalid + */ +w_status_t pwm_update_duty_cycle(uint8_t ccp_module, uint16_t duty_cycle); #endif /* ROCKETLIB_PWM_H */ diff --git a/pic18f26k83/pwm.c b/pic18f26k83/pwm.c index 6b2794f..d035bfe 100644 --- a/pic18f26k83/pwm.c +++ b/pic18f26k83/pwm.c @@ -1,66 +1,98 @@ #include "pwm.h" #include -// Helper function to configure PPS registers using macros -static w_status_t configure_pps(uint8_t ccp_module, pwm_pin_config_t pin_config) { - volatile uint8_t *pps_reg; - - // Ensure the CCP module number is within valid range (1-4) - if (ccp_module < 1 || ccp_module > 4) { - return W_INVALID_PARAM; // Return error if the module number is out of range +/** + * @brief Get CCPR Low register address for the specified CCP module + */ +static volatile uint8_t* get_ccpr_low_register(uint8_t ccp_module) { + switch (ccp_module) { + case 1U: return &CCPR1L; + case 2U: return &CCPR2L; + case 3U: return &CCPR3L; + case 4U: return &CCPR4L; + case 5U: return &CCPR5L; + default: return NULL; } +} - // Set the pin as output to drive PWM signal - // This macro modifies the TRIS register to set the specified pin as an output - SET_TRIS_OUTPUT(pin_config.port, pin_config.pin); - - // Assign the CCP module to the corresponding PPS register - // This macro sets up the peripheral pin select to link the CCP module to the desired pin - ASSIGN_PPS(pin_config.port, pin_config.pin, ccp_module); +/** + * @brief Get CCPR High register address for the specified CCP module + */ +static volatile uint8_t* get_ccpr_high_register(uint8_t ccp_module) { + switch (ccp_module) { + case 1U: return &CCPR1H; + case 2U: return &CCPR2H; + case 3U: return &CCPR3H; + case 4U: return &CCPR4H; + case 5U: return &CCPR5H; + default: return NULL; + } +} - return W_SUCCESS; // Return success status after configuring PPS +/** + * @brief Get CCPxCON register address for the specified CCP module + */ +static volatile uint8_t* get_ccp_con_register(uint8_t ccp_module) { + switch (ccp_module) { + case 1U: return &CCP1CON; + case 2U: return &CCP2CON; + case 3U: return &CCP3CON; + case 4U: return &CCP4CON; + case 5U: return &CCP5CON; + default: return NULL; + } } -// Initialize PWM for a specific CCP module -w_status_t pwm_init(uint8_t ccp_module, pwm_pin_config_t pin_config, uint16_t pwm_period) { - // Configure PPS registers to map CCP module to the selected pin - w_status_t status = configure_pps(ccp_module, pin_config); - if (status != W_SUCCESS) { - return status; // Return error status if PPS configuration fails +w_status_t pwm_init(uint8_t ccp_module, uint16_t pwm_period) { + // Validate CCP module + if (ccp_module < 1U || ccp_module > 5U) { + return W_INVALID_PARAM; } - // Obtain the address of the CCPxCON register using macro - volatile uint8_t *ccp_con = &CCP_CON(ccp_module); - *ccp_con = 0x8C; // Enable CCP module in PWM mode (PWM mode selection) + // Get the CCPxCON register for this module + volatile uint8_t *ccp_con = get_ccp_con_register(ccp_module); + if (ccp_con == NULL) { + return W_INVALID_PARAM; + } + + // Enable CCP module in PWM mode + *ccp_con = 0x8CU; // PWM mode selection // Set PWM period using Timer2 - PR2 = pwm_period & 0xFF; // Load lower 8 bits of PWM period into PR2 register - TMR2 = 0; // Reset Timer2 count to 0 - T2CONbits.T2CKPS = 0; // Set Timer2 prescaler to 1:1 (no prescaling) - T2CONbits.TOUTPS = 0; // Set Timer2 postscaler to 1:1 (no postscaling) - T2CONbits.TMR2ON = 1; // Start Timer2 to begin PWM operation + PR2 = (uint8_t)(pwm_period & 0xFFU); // Load lower 8 bits of PWM period into PR2 register + TMR2 = 0U; // Reset Timer2 count to 0 + T2CONbits.T2CKPS = 0U; // Set Timer2 prescaler to 1:1 (no prescaling) + T2CONbits.TOUTPS = 0U; // Set Timer2 postscaler to 1:1 (no postscaling) + T2CONbits.TMR2ON = 1U; // Start Timer2 to begin PWM operation // Wait for Timer2 to reach the period value before starting PWM - while (!PIR1bits.TMR2IF) {} // Wait until Timer2 overflow flag is set - PIR1bits.TMR2IF = 0; // Clear Timer2 interrupt flag to continue + while (PIR1bits.TMR2IF == 0U) { + // Wait until Timer2 overflow flag is set + } + PIR1bits.TMR2IF = 0U; // Clear Timer2 interrupt flag to continue - return W_SUCCESS; // Return success status after PWM initialization + return W_SUCCESS; } -// Update the duty cycle of a specific CCP module w_status_t pwm_update_duty_cycle(uint8_t ccp_module, uint16_t duty_cycle) { // Validate CCP module and duty cycle range - if (ccp_module < 1 || ccp_module > 4 || duty_cycle > 1023) { - return W_INVALID_PARAM; // Return error if module number or duty cycle is out of range + if (ccp_module < 1U || ccp_module > 5U || duty_cycle > 1023U) { + return W_INVALID_PARAM; + } + + // Get register addresses + volatile uint8_t *ccpr_low = get_ccpr_low_register(ccp_module); + volatile uint8_t *ccpr_high = get_ccpr_high_register(ccp_module); + + if (ccpr_low == NULL || ccpr_high == NULL) { + return W_INVALID_PARAM; } // Update the lower 8 bits of the duty cycle - // This sets the low byte of the duty cycle for the PWM signal - CCPR_L(ccp_module) = duty_cycle & 0xFF; + *ccpr_low = (uint8_t)(duty_cycle & 0xFFU); // Update the upper 2 bits of the duty cycle for 10-bit resolution - // This sets the high bits of the duty cycle to achieve 10-bit PWM precision - CCPR_H(ccp_module) = (duty_cycle >> 8) & 0x03; + *ccpr_high = (uint8_t)((duty_cycle >> 8) & 0x03U); - return W_SUCCESS; // Return success status after updating duty cycle + return W_SUCCESS; } From 7888f4fea0c97194ca9757a43f0c32b0c300398f Mon Sep 17 00:00:00 2001 From: taisirhassan Date: Sat, 31 May 2025 03:31:00 -0400 Subject: [PATCH 6/9] Add comprehensive pin configuration structures and dynamic configuration functions This commit expands the pin_config.h file by introducing structures for I2C, SPI, UART, PWM, and external interrupt pin configurations. It also adds functions for dynamically configuring these pins, enhancing the Peripheral Pin Select (PPS) capabilities. --- include/pin_config.h | 129 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 122 insertions(+), 7 deletions(-) diff --git a/include/pin_config.h b/include/pin_config.h index 6cb651e..3e9d961 100644 --- a/include/pin_config.h +++ b/include/pin_config.h @@ -2,18 +2,133 @@ #define ROCKETLIB_PIN_CONFIG_H #include "common.h" +#include + +// Structure to hold pin configuration details +typedef struct { + uint8_t port; // Port number (0=A, 1=B, 2=C) + uint8_t pin; // Pin number (0-7) +} pin_config_t; + +// Structure for I2C pin configuration +typedef struct { + pin_config_t scl; // SCL pin configuration + pin_config_t sda; // SDA pin configuration +} i2c_pin_config_t; + +// Structure for SPI pin configuration +typedef struct { + pin_config_t sck; // Clock pin configuration + pin_config_t sdi; // Data input pin configuration + pin_config_t sdo; // Data output pin configuration + pin_config_t ss; // Slave select pin configuration (optional) +} spi_pin_config_t; + +// Structure for UART pin configuration +typedef struct { + pin_config_t tx; // Transmit pin configuration + pin_config_t rx; // Receive pin configuration +} uart_pin_config_t; + +// Structure for PWM pin configuration +typedef struct { + pin_config_t output; // PWM output pin configuration +} pwm_pin_config_t; + +// Structure for external interrupt pin configuration +typedef struct { + pin_config_t input; // External interrupt input pin configuration +} ext_int_pin_config_t; + +// PPS input and output codes for different peripherals +// I2C PPS codes +#define PPS_I2C1_SCL_OUTPUT 0b100001 +#define PPS_I2C1_SDA_OUTPUT 0b100010 +#define PPS_I2C2_SCL_OUTPUT 0b100011 +#define PPS_I2C2_SDA_OUTPUT 0b100100 + +// SPI PPS codes +#define PPS_SPI1_SCK_OUTPUT 0b011110 +#define PPS_SPI1_SDO_OUTPUT 0b011111 +#define PPS_SPI2_SCK_OUTPUT 0b100000 +#define PPS_SPI2_SDO_OUTPUT 0b100001 + +// UART PPS codes +#define PPS_UART1_TX_OUTPUT 0b010011 +#define PPS_UART2_TX_OUTPUT 0b010100 +#define PPS_UART3_TX_OUTPUT 0b010101 +#define PPS_UART4_TX_OUTPUT 0b010110 +#define PPS_UART5_TX_OUTPUT 0b010111 + +// PWM/CCP PPS codes +#define PPS_CCP1_OUTPUT 0b001100 +#define PPS_CCP2_OUTPUT 0b001101 +#define PPS_CCP3_OUTPUT 0b001110 +#define PPS_CCP4_OUTPUT 0b001111 +#define PPS_CCP5_OUTPUT 0b010000 + +/** + * @brief Configure I2C pins dynamically + * + * @param i2c_module I2C module number (1-2) + * @param pin_config I2C pin configuration structure + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if parameters are invalid + */ +w_status_t pps_configure_i2c(uint8_t i2c_module, i2c_pin_config_t pin_config); + +/** + * @brief Configure SPI pins dynamically for master mode + * + * @param spi_module SPI module number (1-2) + * @param pin_config SPI pin configuration structure + * @param use_ss Whether to configure slave select pin + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if parameters are invalid + */ +w_status_t pps_configure_spi(uint8_t spi_module, spi_pin_config_t pin_config, bool use_ss); + +/** + * @brief Configure UART pins dynamically + * + * @param uart_module UART module number (1-5) + * @param pin_config UART pin configuration structure + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if parameters are invalid + */ +w_status_t pps_configure_uart(uint8_t uart_module, uart_pin_config_t pin_config); + +/** + * @brief Configure PWM/CCP pins dynamically + * + * @param ccp_module CCP module number (1-5) + * @param pin_config PWM pin configuration structure + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if parameters are invalid + */ +w_status_t pps_configure_pwm(uint8_t ccp_module, pwm_pin_config_t pin_config); /** - * @brief Initializes the Peripheral Pin Select (PPS) configuration + * @brief Configure external interrupt pins dynamically * - * This function sets up all PPS mappings for peripherals including I2C, SPI, UART, and Timer - * inputs. Note that PWM/CCP PPS configuration is handled by the PWM module itself when pwm_init() - * is called. + * @param int_number External interrupt number (0-2 for INT0, INT1, INT2) + * @param pin_config External interrupt pin configuration structure + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if parameters are invalid + */ +w_status_t pps_configure_external_interrupt(uint8_t int_number, ext_int_pin_config_t pin_config); + +/** + * @brief Configure timer external clock input * - * Should be called after basic MCU initialization (mcu_init) but before peripheral initialization. + * @param timer Timer number (0, 1, 2, 3, 4, 5, 6) + * @param pin_config Pin configuration for the external clock input + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if parameters are invalid + */ +w_status_t pps_configure_timer_clk(uint8_t timer, pin_config_t pin_config); + +/** + * @brief Configure timer gate input * - * @return w_status_t W_SUCCESS if successful + * @param timer Timer number (0, 1, 2, 3, 4, 5, 6) + * @param pin_config Pin configuration for the timer gate input + * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if parameters are invalid */ -w_status_t pin_init(void); +w_status_t pps_configure_timer_gate(uint8_t timer, pin_config_t pin_config); #endif /* ROCKETLIB_PIN_CONFIG_H */ \ No newline at end of file From 16835ba81427cb475e8ed3843f35fb4fa254ffcc Mon Sep 17 00:00:00 2001 From: taisirhassan Date: Sat, 31 May 2025 03:44:13 -0400 Subject: [PATCH 7/9] Add functions for dynamic pin configuration and enhance PPS handling This commit introduces several new functions for configuring pins dynamically, including support for I2C, SPI, UART, and PWM. It also adds validation for pin configurations and improves the handling of Peripheral Pin Select (PPS) mappings, ensuring safe modifications by unlocking and locking PPS registers as needed. --- include/pin_config.h | 1 + pic18f26k83/pin_config.c | 839 ++++++++++++++++++++++++++++++--------- 2 files changed, 663 insertions(+), 177 deletions(-) diff --git a/include/pin_config.h b/include/pin_config.h index 3e9d961..3752fd0 100644 --- a/include/pin_config.h +++ b/include/pin_config.h @@ -3,6 +3,7 @@ #include "common.h" #include +#include // Structure to hold pin configuration details typedef struct { diff --git a/pic18f26k83/pin_config.c b/pic18f26k83/pin_config.c index 12ae27d..8cdb63c 100644 --- a/pic18f26k83/pin_config.c +++ b/pic18f26k83/pin_config.c @@ -4,264 +4,749 @@ /** * @brief Unlocks the PPS registers for configuration - * - * Implements the specific sequence from the PIC18F26K83 datasheet - * to unlock the PPS registers for modification. - * - * @return w_status_t W_SUCCESS if successful */ static w_status_t pps_unlock(void) { + uint8_t gie_state = INTCON0bits.GIE; // Save current GIE state INTCON0bits.GIE = 0; // Disable global interrupts during critical sequence PPSLOCK = 0x55; // First unlock sequence value PPSLOCK = 0xAA; // Second unlock sequence value PPSLOCKbits.PPSLOCKED = 0; // Clear PPSLOCKED bit to enable PPS changes - INTCON0bits.GIE = 1; // Re-enable global interrupts - + INTCON0bits.GIE = gie_state; // Restore original GIE state return W_SUCCESS; } /** * @brief Locks the PPS registers to prevent accidental changes - * - * Implements the specific sequence from the PIC18F26K83 datasheet - * to lock the PPS registers after configuration is complete. - * - * @return w_status_t W_SUCCESS if successful */ static w_status_t pps_lock(void) { + uint8_t gie_state = INTCON0bits.GIE; // Save current GIE state INTCON0bits.GIE = 0; // Disable global interrupts during critical sequence PPSLOCK = 0x55; // First lock sequence value PPSLOCK = 0xAA; // Second lock sequence value PPSLOCKbits.PPSLOCKED = 1; // Set PPSLOCKED bit to lock PPS registers - INTCON0bits.GIE = 1; // Re-enable global interrupts - + INTCON0bits.GIE = gie_state; // Restore original GIE state return W_SUCCESS; } /** - * @brief Helper function for PPS input mapping - * - * Sets up the mapping between a peripheral input and a physical pin. - * - * @param pps_register Pointer to the peripheral's PPS register - * @param port_pin_code Code representing the port and pin (format: 0bPPPNNN where PPP=port, - * NNN=pin) - * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if pointer is NULL + * @brief Get TRIS register address for the specified port */ -static w_status_t pps_input(volatile unsigned char *pps_register, unsigned char port_pin_code) { - if (pps_register == NULL) { - return W_INVALID_PARAM; +static volatile uint8_t* get_tris_register(uint8_t port) { + switch (port) { + case 0U: return &TRISA; + case 1U: return &TRISB; + case 2U: return &TRISC; + default: return NULL; } +} - *pps_register = port_pin_code; - return W_SUCCESS; +/** + * @brief Get ANSEL register address for the specified port + */ +static volatile uint8_t* get_ansel_register(uint8_t port) { + switch (port) { + case 0U: return &ANSELA; + case 1U: return &ANSELB; + case 2U: return &ANSELC; + default: return NULL; + } } /** - * @brief Helper function for PPS output mapping - * - * Sets up the mapping between a peripheral output and a physical pin. - * - * @param rxy_pps_register Pointer to the pin's PPS register - * @param peripheral_code Code representing the peripheral output function - * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if pointer is NULL + * @brief Get ODCON register address for the specified port */ -static w_status_t -pps_output(volatile unsigned char *rxy_pps_register, unsigned char peripheral_code) { - if (rxy_pps_register == NULL) { - return W_INVALID_PARAM; +static volatile uint8_t* get_odcon_register(uint8_t port) { + switch (port) { + case 0U: return &ODCONA; + case 1U: return &ODCONB; + case 2U: return &ODCONC; + default: return NULL; } +} - *rxy_pps_register = peripheral_code; +/** + * @brief Get PPS output register address for the specified port and pin + */ +static volatile uint8_t* get_pps_output_register(uint8_t port, uint8_t pin) { + if (port == 0U) { // PORTA + switch (pin) { + case 0U: return &RA0PPS; + case 1U: return &RA1PPS; + case 2U: return &RA2PPS; + case 3U: return &RA3PPS; + case 4U: return &RA4PPS; + case 5U: return &RA5PPS; + case 6U: return &RA6PPS; + case 7U: return &RA7PPS; + default: return NULL; + } + } else if (port == 1U) { // PORTB + switch (pin) { + case 0U: return &RB0PPS; + case 1U: return &RB1PPS; + case 2U: return &RB2PPS; + case 3U: return &RB3PPS; + case 4U: return &RB4PPS; + case 5U: return &RB5PPS; + case 6U: return &RB6PPS; + case 7U: return &RB7PPS; + default: return NULL; + } + } else if (port == 2U) { // PORTC + switch (pin) { + case 0U: return &RC0PPS; + case 1U: return &RC1PPS; + case 2U: return &RC2PPS; + case 3U: return &RC3PPS; + case 4U: return &RC4PPS; + case 5U: return &RC5PPS; + case 6U: return &RC6PPS; + case 7U: return &RC7PPS; + default: return NULL; + } + } + return NULL; +} + +/** + * @brief Validate pin configuration parameters + */ +static w_status_t validate_pin_config(pin_config_t pin_config) { + if (pin_config.port > 2U || pin_config.pin > 7U) { + return W_INVALID_PARAM; + } return W_SUCCESS; } /** - * @brief Configures I2C1 pins for RC3 (SCL) and RC4 (SDA) - * - * Sets up PPS registers for the I2C1 module on the PIC18F26K83. - * Configures both input and output mappings since I2C is bidirectional. - * Also configures pins for digital mode and open-drain operation. - * - * @return w_status_t W_SUCCESS if successful + * @brief Configure a pin for digital I/O */ -static w_status_t pps_configure_i2c1(void) { - // Configure digital mode for I2C pins - ANSELCbits.ANSC3 = 0; // Set RC3 to digital mode - ANSELCbits.ANSC4 = 0; // Set RC4 to digital mode +static w_status_t configure_pin_digital(pin_config_t pin_config, uint8_t direction) { + w_status_t status = validate_pin_config(pin_config); + if (status != W_SUCCESS) { + return status; + } - // Set pins as inputs initially (I2C peripheral will control them) - TRISCbits.TRISC3 = 1; // Set SCL as input - TRISCbits.TRISC4 = 1; // Set SDA as input + volatile uint8_t *ansel_reg = get_ansel_register(pin_config.port); + volatile uint8_t *tris_reg = get_tris_register(pin_config.port); - // Input mapping for I2C (from pins to peripheral) - I2C1SCLPPS = 0b010011; // Map RC3 to I2C1 SCL input - I2C1SDAPPS = 0b010100; // Map RC4 to I2C1 SDA input + if (ansel_reg == NULL || tris_reg == NULL) { + return W_INVALID_PARAM; + } - // Output mapping for I2C (from peripheral to pins) - RC3PPS = 0b100001; // Map I2C1 SCL output to RC3 - RC4PPS = 0b100010; // Map I2C1 SDA output to RC4 + // Set pin to digital mode + *ansel_reg &= ~(1U << pin_config.pin); - // Enable open-drain mode for I2C pins (required for I2C operation) - ODCONCbits.ODCC3 = 1; // Set RC3 to open-drain mode - ODCONCbits.ODCC4 = 1; // Set RC4 to open-drain mode + // Set direction (0=output, 1=input) + if (direction != 0U) { + *tris_reg |= (1U << pin_config.pin); + } else { + *tris_reg &= ~(1U << pin_config.pin); + } return W_SUCCESS; } /** - * @brief Configures SPI1 pins for master mode - * - * Sets up PPS registers for the SPI1 module in master mode: - * - RB1 (SCK) - Clock output - * - RB2 (SDI) - Data input - * - RB3 (SDO) - Data output - * - * Also configures pin directions and digital mode appropriately. - * - * @return w_status_t W_SUCCESS if successful + * @brief Set pin to open-drain mode */ -static w_status_t pps_configure_spi1(void) { - // Configure digital mode for SPI pins - ANSELBbits.ANSELB1 = 0; // Set RB1 to digital mode - ANSELBbits.ANSELB2 = 0; // Set RB2 to digital mode - ANSELBbits.ANSELB3 = 0; // Set RB3 to digital mode +static w_status_t configure_pin_open_drain(pin_config_t pin_config) { + w_status_t status = validate_pin_config(pin_config); + if (status != W_SUCCESS) { + return status; + } - // Set correct pin directions for SPI master mode - TRISBbits.TRISB1 = 0; // SCK as output (master mode) - TRISBbits.TRISB2 = 1; // SDI as input (master reads data) - TRISBbits.TRISB3 = 0; // SDO as output (master sends data) + volatile uint8_t *odcon_reg = get_odcon_register(pin_config.port); + if (odcon_reg == NULL) { + return W_INVALID_PARAM; + } - // Input mapping for SPI (from pins to peripheral) - SPI1SCKPPS = 0b001001; // Map RB1 to SPI1 SCK input (for slave mode or feedback) - SPI1SDIPPS = 0b001010; // Map RB2 to SPI1 SDI input + *odcon_reg |= (1U << pin_config.pin); + return W_SUCCESS; +} - // Output mapping for SPI (from peripheral to pins) - RB1PPS = 0b011110; // Map SPI1 SCK output to RB1 - RB3PPS = 0b011111; // Map SPI1 SDO output to RB3 +/** + * @brief Get port-pin code for PPS input mapping + */ +static uint8_t get_port_pin_code(pin_config_t pin_config) { + return (uint8_t)((pin_config.port << 3) | pin_config.pin); +} + +/** + * @brief Configure PPS output mapping + */ +static w_status_t configure_pps_output(pin_config_t pin_config, uint8_t peripheral_code) { + w_status_t status = validate_pin_config(pin_config); + if (status != W_SUCCESS) { + return status; + } + volatile uint8_t *pps_reg = get_pps_output_register(pin_config.port, pin_config.pin); + if (pps_reg == NULL) { + return W_INVALID_PARAM; + } + + *pps_reg = peripheral_code; return W_SUCCESS; } /** - * @brief Configures UART1 pins for communication - * - * Sets up PPS registers for the UART1 module: - * - RC6 (TX) - Transmit output - * - RC7 (RX) - Receive input - * - * Also configures pin directions and digital mode appropriately. - * - * @return w_status_t W_SUCCESS if successful + * @brief Get I2C PPS codes for the specified module */ -static w_status_t pps_configure_uart1(void) { - // Configure digital mode for UART pins - ANSELCbits.ANSC6 = 0; // Set RC6 to digital mode - ANSELCbits.ANSC7 = 0; // Set RC7 to digital mode +static w_status_t get_i2c_pps_codes(uint8_t i2c_module, uint8_t *scl_code, uint8_t *sda_code) { + switch (i2c_module) { + case 1U: + *scl_code = PPS_I2C1_SCL_OUTPUT; + *sda_code = PPS_I2C1_SDA_OUTPUT; + return W_SUCCESS; + case 2U: + *scl_code = PPS_I2C2_SCL_OUTPUT; + *sda_code = PPS_I2C2_SDA_OUTPUT; + return W_SUCCESS; + default: + return W_INVALID_PARAM; + } +} - // Set correct pin directions for UART - TRISCbits.TRISC6 = 0; // TX as output - TRISCbits.TRISC7 = 1; // RX as input +/** + * @brief Configure I2C PPS input registers + */ +static w_status_t configure_i2c_input_pps(uint8_t i2c_module, i2c_pin_config_t pin_config) { + uint8_t scl_port_pin_code = get_port_pin_code(pin_config.scl); + uint8_t sda_port_pin_code = get_port_pin_code(pin_config.sda); + + switch (i2c_module) { + case 1U: + I2C1SCLPPS = scl_port_pin_code; + I2C1SDAPPS = sda_port_pin_code; + return W_SUCCESS; + case 2U: + I2C2SCLPPS = scl_port_pin_code; + I2C2SDAPPS = sda_port_pin_code; + return W_SUCCESS; + default: + return W_INVALID_PARAM; + } +} - // Input mapping for UART (from pin to peripheral) - U1RXPPS = 0b010111; // Map RC7 to UART1 RX input +/** + * @brief Get SPI PPS codes for the specified module + */ +static w_status_t get_spi_pps_codes(uint8_t spi_module, uint8_t *sck_code, uint8_t *sdo_code) { + switch (spi_module) { + case 1U: + *sck_code = PPS_SPI1_SCK_OUTPUT; + *sdo_code = PPS_SPI1_SDO_OUTPUT; + return W_SUCCESS; + case 2U: + *sck_code = PPS_SPI2_SCK_OUTPUT; + *sdo_code = PPS_SPI2_SDO_OUTPUT; + return W_SUCCESS; + default: + return W_INVALID_PARAM; + } +} - // Output mapping for UART (from peripheral to pin) - RC6PPS = 0b010011; // Map UART1 TX output to RC6 +/** + * @brief Configure SPI PPS input registers + */ +static w_status_t configure_spi_input_pps(uint8_t spi_module, spi_pin_config_t pin_config) { + uint8_t sck_port_pin_code = get_port_pin_code(pin_config.sck); + uint8_t sdi_port_pin_code = get_port_pin_code(pin_config.sdi); + + switch (spi_module) { + case 1U: + SPI1SCKPPS = sck_port_pin_code; + SPI1SDIPPS = sdi_port_pin_code; + return W_SUCCESS; + case 2U: + SPI2SCKPPS = sck_port_pin_code; + SPI2SDIPPS = sdi_port_pin_code; + return W_SUCCESS; + default: + return W_INVALID_PARAM; + } +} - return W_SUCCESS; +/** + * @brief Configure UART PPS input registers + */ +static w_status_t configure_uart_input_pps(uint8_t uart_module, pin_config_t rx_pin) { + uint8_t rx_port_pin_code = get_port_pin_code(rx_pin); + + switch (uart_module) { + case 1U: + U1RXPPS = rx_port_pin_code; + return W_SUCCESS; + case 2U: + U2RXPPS = rx_port_pin_code; + return W_SUCCESS; + case 3U: + U3RXPPS = rx_port_pin_code; + return W_SUCCESS; + case 4U: + U4RXPPS = rx_port_pin_code; + return W_SUCCESS; + case 5U: + U5RXPPS = rx_port_pin_code; + return W_SUCCESS; + default: + return W_INVALID_PARAM; + } } /** - * @brief Configures timer external clock inputs - * - * Maps a physical pin to serve as the external clock input for a timer. - * Also configures the pin as a digital input. - * - * @param timer Timer number to configure (0, 1, 3, 5) - * @param port Port number where clock input is located (0=PORTA, 1=PORTB, 2=PORTC) - * @param pin Pin number within the port (0-7) - * @return w_status_t W_SUCCESS if successful, W_INVALID_PARAM if parameters are invalid + * @brief Get UART TX PPS code for the specified module */ -static w_status_t -pps_configure_timer_clk(unsigned char timer, unsigned char port, unsigned char pin) { - // Create the port-pin PPS input code (format: 0bPPPPPP where bits 5-3=port, bits 2-0=pin) - unsigned char port_pin_code = (port << 3) | pin; +static w_status_t get_uart_tx_pps_code(uint8_t uart_module, uint8_t *tx_code) { + switch (uart_module) { + case 1U: + *tx_code = PPS_UART1_TX_OUTPUT; + return W_SUCCESS; + case 2U: + *tx_code = PPS_UART2_TX_OUTPUT; + return W_SUCCESS; + case 3U: + *tx_code = PPS_UART3_TX_OUTPUT; + return W_SUCCESS; + case 4U: + *tx_code = PPS_UART4_TX_OUTPUT; + return W_SUCCESS; + case 5U: + *tx_code = PPS_UART5_TX_OUTPUT; + return W_SUCCESS; + default: + return W_INVALID_PARAM; + } +} - // Configure the pin for digital input - switch (port) { - case 0: // PORTA - if (pin < 8) { - ANSELA &= ~(1 << pin); // Set pin to digital mode - TRISA |= (1 << pin); // Set pin as input - } +/** + * @brief Get CCP PPS code for the specified module + */ +static w_status_t get_ccp_pps_code(uint8_t ccp_module, uint8_t *pps_code) { + switch (ccp_module) { + case 1U: + *pps_code = PPS_CCP1_OUTPUT; + return W_SUCCESS; + case 2U: + *pps_code = PPS_CCP2_OUTPUT; + return W_SUCCESS; + case 3U: + *pps_code = PPS_CCP3_OUTPUT; + return W_SUCCESS; + case 4U: + *pps_code = PPS_CCP4_OUTPUT; + return W_SUCCESS; + case 5U: + *pps_code = PPS_CCP5_OUTPUT; + return W_SUCCESS; + default: + return W_INVALID_PARAM; + } +} + +w_status_t pps_configure_i2c(uint8_t i2c_module, i2c_pin_config_t pin_config) { + w_status_t status; + w_status_t final_status = W_SUCCESS; + uint8_t scl_pps_code, sda_pps_code; + + // Validate module number + if (i2c_module < 1U || i2c_module > 2U) { + return W_INVALID_PARAM; + } + + // Get PPS codes for this I2C module + status = get_i2c_pps_codes(i2c_module, &scl_pps_code, &sda_pps_code); + if (status != W_SUCCESS) { + return status; + } + + // Unlock PPS registers + status = pps_unlock(); + if (status != W_SUCCESS) { + return status; + } + + // Configure SCL pin + status = configure_pin_digital(pin_config.scl, 1U); // Input initially + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + status = configure_pin_open_drain(pin_config.scl); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure SDA pin + status = configure_pin_digital(pin_config.sda, 1U); // Input initially + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + status = configure_pin_open_drain(pin_config.sda); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure PPS input mappings + status = configure_i2c_input_pps(i2c_module, pin_config); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure PPS output mappings + status = configure_pps_output(pin_config.scl, scl_pps_code); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + status = configure_pps_output(pin_config.sda, sda_pps_code); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + +cleanup: + // Always lock PPS registers before returning + pps_lock(); + return final_status; +} + +w_status_t pps_configure_spi(uint8_t spi_module, spi_pin_config_t pin_config, bool use_ss) { + w_status_t status; + w_status_t final_status = W_SUCCESS; + uint8_t sck_pps_code, sdo_pps_code; + + // Validate module number + if (spi_module < 1U || spi_module > 2U) { + return W_INVALID_PARAM; + } + + // Get PPS codes for this SPI module + status = get_spi_pps_codes(spi_module, &sck_pps_code, &sdo_pps_code); + if (status != W_SUCCESS) { + return status; + } + + // Unlock PPS registers + status = pps_unlock(); + if (status != W_SUCCESS) { + return status; + } + + // Configure SCK pin (output for master mode) + status = configure_pin_digital(pin_config.sck, 0U); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure SDI pin (input for master mode) + status = configure_pin_digital(pin_config.sdi, 1U); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure SDO pin (output for master mode) + status = configure_pin_digital(pin_config.sdo, 0U); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure SS pin if requested (output for master mode) + if (use_ss) { + status = configure_pin_digital(pin_config.ss, 0U); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + } + + // Configure PPS input mappings + status = configure_spi_input_pps(spi_module, pin_config); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure PPS output mappings + status = configure_pps_output(pin_config.sck, sck_pps_code); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + status = configure_pps_output(pin_config.sdo, sdo_pps_code); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + +cleanup: + // Always lock PPS registers before returning + pps_lock(); + return final_status; +} + +w_status_t pps_configure_uart(uint8_t uart_module, uart_pin_config_t pin_config) { + w_status_t status; + w_status_t final_status = W_SUCCESS; + uint8_t tx_pps_code; + + // Validate module number + if (uart_module < 1U || uart_module > 5U) { + return W_INVALID_PARAM; + } + + // Get TX PPS code for this UART module + status = get_uart_tx_pps_code(uart_module, &tx_pps_code); + if (status != W_SUCCESS) { + return status; + } + + // Unlock PPS registers + status = pps_unlock(); + if (status != W_SUCCESS) { + return status; + } + + // Configure TX pin (output) + status = configure_pin_digital(pin_config.tx, 0U); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure RX pin (input) + status = configure_pin_digital(pin_config.rx, 1U); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure PPS input mapping + status = configure_uart_input_pps(uart_module, pin_config.rx); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure PPS output mapping + status = configure_pps_output(pin_config.tx, tx_pps_code); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + +cleanup: + // Always lock PPS registers before returning + pps_lock(); + return final_status; +} + +w_status_t pps_configure_pwm(uint8_t ccp_module, pwm_pin_config_t pin_config) { + w_status_t status; + w_status_t final_status = W_SUCCESS; + uint8_t pps_code; + + // Validate module number + if (ccp_module < 1U || ccp_module > 5U) { + return W_INVALID_PARAM; + } + + // Get PPS code for this CCP module + status = get_ccp_pps_code(ccp_module, &pps_code); + if (status != W_SUCCESS) { + return status; + } + + // Unlock PPS registers + status = pps_unlock(); + if (status != W_SUCCESS) { + return status; + } + + // Configure output pin (PWM output) + status = configure_pin_digital(pin_config.output, 0U); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure PPS output mapping + status = configure_pps_output(pin_config.output, pps_code); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + +cleanup: + // Always lock PPS registers before returning + pps_lock(); + return final_status; +} + +w_status_t pps_configure_external_interrupt(uint8_t int_number, ext_int_pin_config_t pin_config) { + w_status_t status; + w_status_t final_status = W_SUCCESS; + + // Validate interrupt number (INT0, INT1, INT2) + if (int_number > 2U) { + return W_INVALID_PARAM; + } + + // Unlock PPS registers + status = pps_unlock(); + if (status != W_SUCCESS) { + return status; + } + + // Configure pin as digital input + status = configure_pin_digital(pin_config.input, 1U); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure PPS input mapping based on interrupt number + uint8_t port_pin_code = get_port_pin_code(pin_config.input); + switch (int_number) { + case 0U: + INT0PPS = port_pin_code; break; - case 1: // PORTB - if (pin < 8) { - ANSELB &= ~(1 << pin); // Set pin to digital mode - TRISB |= (1 << pin); // Set pin as input - } + case 1U: + INT1PPS = port_pin_code; break; - case 2: // PORTC - if (pin < 8) { - ANSELC &= ~(1 << pin); // Set pin to digital mode - TRISC |= (1 << pin); // Set pin as input - } + case 2U: + INT2PPS = port_pin_code; break; default: - return; // Invalid port + final_status = W_INVALID_PARAM; + goto cleanup; } - // Map the pin to the appropriate timer input +cleanup: + // Always lock PPS registers before returning + pps_lock(); + return final_status; +} + +w_status_t pps_configure_timer_clk(uint8_t timer, pin_config_t pin_config) { + w_status_t status; + w_status_t final_status = W_SUCCESS; + + // Validate timer number (expanded to support more timers) + if (timer > 6U) { + return W_INVALID_PARAM; + } + + // Unlock PPS registers + status = pps_unlock(); + if (status != W_SUCCESS) { + return status; + } + + // Configure pin as digital input + status = configure_pin_digital(pin_config, 1U); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } + + // Configure PPS input mapping based on timer + uint8_t port_pin_code = get_port_pin_code(pin_config); switch (timer) { - case 0: - T0CKIPPS = port_pin_code; // Timer0 external clock input + case 0U: + T0CKIPPS = port_pin_code; + break; + case 1U: + T1CKIPPS = port_pin_code; break; - case 1: - T1CKIPPS = port_pin_code; // Timer1 external clock input + case 2U: + T2CKIPPS = port_pin_code; break; - case 3: - T3CKIPPS = port_pin_code; // Timer3 external clock input + case 3U: + T3CKIPPS = port_pin_code; break; - case 5: - T5CKIPPS = port_pin_code; // Timer5 external clock input + case 4U: + T4CKIPPS = port_pin_code; + break; + case 5U: + T5CKIPPS = port_pin_code; + break; + case 6U: + T6CKIPPS = port_pin_code; break; default: - return W_INVALID_PARAM; // Invalid timer + final_status = W_INVALID_PARAM; + goto cleanup; } - return W_SUCCESS; +cleanup: + // Always lock PPS registers before returning + pps_lock(); + return final_status; } -/** - * @brief Initializes all PPS configurations for peripherals - * - * This function sets up all Peripheral Pin Select (PPS) mappings - * for the PIC18F26K83 microcontroller. It configures: - * - I2C1 pins (RC3/RC4) - * - SPI1 pins (RB1/RB2/RB3) - * - UART1 pins (RC6/RC7) - * - * Note that PWM/CCP PPS configuration is handled by the PWM module itself. - * This function should be called after basic MCU initialization but before - * initializing any peripherals. - * - * @return w_status_t W_SUCCESS if successful - */ -w_status_t pin_init(void) { - // Unlock PPS registers before making any changes - pps_unlock(); +w_status_t pps_configure_timer_gate(uint8_t timer, pin_config_t pin_config) { + w_status_t status; + w_status_t final_status = W_SUCCESS; - // Configure all required peripheral pins - pps_configure_i2c1(); - pps_configure_spi1(); - pps_configure_uart1(); + // Validate timer number + if (timer > 6U) { + return W_INVALID_PARAM; + } + + // Unlock PPS registers + status = pps_unlock(); + if (status != W_SUCCESS) { + return status; + } + + // Configure pin as digital input + status = configure_pin_digital(pin_config, 1U); + if (status != W_SUCCESS) { + final_status = status; + goto cleanup; + } - // Note: PWM/CCP PPS configuration is handled by the PWM module (pwm.c) - // When pwm_init() is called, it will configure the necessary PPS settings + // Configure PPS input mapping for timer gate + uint8_t port_pin_code = get_port_pin_code(pin_config); + switch (timer) { + case 0U: + T0GPPS = port_pin_code; + break; + case 1U: + T1GPPS = port_pin_code; + break; + case 2U: + T2GPPS = port_pin_code; + break; + case 3U: + T3GPPS = port_pin_code; + break; + case 4U: + T4GPPS = port_pin_code; + break; + case 5U: + T5GPPS = port_pin_code; + break; + case 6U: + T6GPPS = port_pin_code; + break; + default: + final_status = W_INVALID_PARAM; + goto cleanup; + } - // Lock PPS registers after all configurations +cleanup: + // Always lock PPS registers before returning pps_lock(); + return final_status; +} - return W_SUCCESS; -} \ No newline at end of file From 7624ef670057c755fccc161cf35228190ef4280e Mon Sep 17 00:00:00 2001 From: taisirhassan Date: Sat, 31 May 2025 03:46:09 -0400 Subject: [PATCH 8/9] Enhance Peripheral Pin Select (PPS) documentation and improve pin configuration structures --- doc/pin_config.rst | 639 ++++++++++++++++++++++++++++++++++----- include/pin_config.h | 6 +- pic18f26k83/pin_config.c | 245 ++++++++------- pic18f26k83/pwm.c | 60 ++-- 4 files changed, 745 insertions(+), 205 deletions(-) diff --git a/doc/pin_config.rst b/doc/pin_config.rst index e6349a9..6a7f8b7 100644 --- a/doc/pin_config.rst +++ b/doc/pin_config.rst @@ -4,124 +4,308 @@ Peripheral Pin Select (PPS) Configuration Overview ======== -The Peripheral Pin Select (PPS) module allows connecting peripheral inputs and outputs to -different physical I/O pins on the PIC18F26K83. This module provides a clean interface -for setting up all the necessary PPS configurations at initialization time. +The Peripheral Pin Select (PPS) module provides centralized pin configuration for all digital +peripherals on the PIC18F26K83. This module handles pin configuration for I2C, SPI, UART, PWM, +Timer, and External Interrupt peripherals, following modular programming principles with clear +separation of concerns. -Functions -========= +**Key Features:** -.. c:function:: w_status_t pin_init(void) +* Centralized pin configuration for all digital peripherals +* Support for multiple peripheral instances (I2C1/2, UART1-5, SPI1/2, CCP1-5, Timer0-6) +* Automatic PPS register lock/unlock management with interrupt safety +* Robust error handling with comprehensive cleanup patterns +* BARR-C coding standard compliance (no function-like macros) +* Modular design promoting separation of concerns - :returns: Status code indicating success or failure - :retval: ``W_SUCCESS`` if PPS initialization was successful +The pin configuration module is responsible for: + +* Pin direction (input/output) configuration +* Digital mode selection +* Open-drain configuration for I2C +* PPS input and output mappings +* Multiple module support (I2C1/2, UART1-5, etc.) +* Interrupt-safe PPS register management + +Other peripheral modules (PWM, I2C, SPI, UART) focus purely on their functionality and rely on this +module for pin configuration. + +.. note:: + This module handles only digital peripherals. + + +Data Structures +=============== + +Pin Configuration Structure +--------------------------- +.. c:type:: pin_config_t + + Structure that holds basic pin configuration details. - Initialize Peripheral Pin Select (PPS) configurations for all peripherals. + .. c:member:: uint8_t port - This function configures the appropriate PPS settings for: + Port number (0=PORTA, 1=PORTB, 2=PORTC). + + .. c:member:: uint8_t pin - * I2C1 (SCL on RC3, SDA on RC4) - * SPI1 in master mode (SCK on RB1, SDI on RB2, SDO on RB3) - * UART1 (TX on RC6, RX on RC7) + Pin number (0-7). + +I2C Pin Configuration Structure +------------------------------- +.. c:type:: i2c_pin_config_t + + Structure that holds I2C pin configuration details. + + .. c:member:: pin_config_t scl - Note that PWM/CCP PPS configuration is handled by the PWM module itself when :c:func:`pwm_init` is called. + SCL (Serial Clock) pin configuration structure. + + .. c:member:: pin_config_t sda - This function should be called after basic MCU initialization but before any peripheral initialization. + SDA (Serial Data) pin configuration structure. -Implementation Details -===================================================== +SPI Pin Configuration Structure +------------------------------- +.. c:type:: spi_pin_config_t -Helper Functions -------------------- + Structure that holds SPI pin configuration details. -The implementation includes several helper functions for managing PPS configuration: + .. c:member:: pin_config_t sck + + SCK (Serial Clock) pin configuration structure. + + .. c:member:: pin_config_t sdi + + SDI (Serial Data Input) pin configuration structure. + + .. c:member:: pin_config_t sdo + + SDO (Serial Data Output) pin configuration structure. + + .. c:member:: pin_config_t ss + + SS (Slave Select) pin configuration structure (optional). -.. c:function:: static w_status_t pps_unlock(void) +UART Pin Configuration Structure +-------------------------------- +.. c:type:: uart_pin_config_t - :returns: Status code indicating success or failure - :retval: ``W_SUCCESS`` if unlock operation was successful + Structure that holds UART pin configuration details. + + .. c:member:: pin_config_t tx + + TX (Transmit) pin configuration structure. + + .. c:member:: pin_config_t rx - Internal function that unlocks the PPS registers for configuration. Per the - PIC18F26K83 datasheet, modifying PPS registers requires a specific unlock sequence. + RX (Receive) pin configuration structure. -.. c:function:: static w_status_t pps_lock(void) +PWM Pin Configuration Structure +------------------------------- +.. c:type:: pwm_pin_config_t - :returns: Status code indicating success or failure - :retval: ``W_SUCCESS`` if lock operation was successful + Structure that holds PWM pin configuration details. + + .. c:member:: pin_config_t output - Internal function that locks the PPS registers after configuration to prevent - accidental changes. + PWM output pin configuration structure. -.. c:function:: static w_status_t pps_input(volatile unsigned char* pps_register, unsigned char port_pin_code) +External Interrupt Pin Configuration Structure +---------------------------------------------- +.. c:type:: ext_int_pin_config_t - :param pps_register: Pointer to the peripheral's PPS register - :param port_pin_code: Code representing the port and pin (format: 0bPPPNNN where PPP=port, NNN=pin) - :returns: Status code indicating success or failure - :retval: ``W_SUCCESS`` if mapping was successful - :retval: ``W_INVALID_PARAM`` if pps_register is NULL + Structure that holds external interrupt pin configuration details. + + .. c:member:: pin_config_t input - Helper function for configuring peripheral input pin mappings. + External interrupt input pin configuration structure. + +Functions +========= -.. c:function:: static w_status_t pps_output(volatile unsigned char* rxy_pps_register, unsigned char peripheral_code) +Dynamic I2C Configuration +------------------------- +.. c:function:: w_status_t pps_configure_i2c(uint8_t i2c_module, i2c_pin_config_t pin_config) - :param rxy_pps_register: Pointer to the pin's PPS register - :param peripheral_code: Code representing the peripheral output function + :param i2c_module: I2C module number (1 or 2) + :param pin_config: I2C pin configuration structure :returns: Status code indicating success or failure - :retval: ``W_SUCCESS`` if mapping was successful - :retval: ``W_INVALID_PARAM`` if rxy_pps_register is NULL + :retval: ``W_SUCCESS`` if configuration was successful + :retval: ``W_INVALID_PARAM`` if module number or pin parameters are invalid + + Configure I2C pins dynamically for the specified module. Sets up both input and output + mappings since I2C is bidirectional, configures pins for digital mode and open-drain + operation as required for I2C communication. + + **Features:** - Helper function for configuring peripheral output pin mappings. + * Configures both SCL and SDA pins for open-drain operation + * Sets up bidirectional PPS mappings for I2C communication + * Validates module number (1-2) and pin parameters + * Atomic operation with automatic PPS lock management + +Dynamic SPI Configuration +------------------------- +.. c:function:: w_status_t pps_configure_spi(uint8_t spi_module, spi_pin_config_t pin_config, bool use_ss) + + :param spi_module: SPI module number (1 or 2) + :param pin_config: SPI pin configuration structure + :param use_ss: Whether to configure slave select pin + :returns: Status code indicating success or failure + :retval: ``W_SUCCESS`` if configuration was successful + :retval: ``W_INVALID_PARAM`` if module number or pin parameters are invalid -Peripheral Configuration Functions -------------------------------------------------- + Configure SPI pins dynamically for master mode operation. Sets up appropriate pin + directions (SCK and SDO as outputs, SDI as input) and PPS mappings. Optionally + configures slave select pin. + + **Features:** + + * Configures pins for SPI master mode operation + * Optional slave select (SS) pin configuration + * Validates module number (1-2) and pin parameters + * Proper input/output pin direction setup -.. c:function:: static w_status_t pps_configure_i2c1(void) +Dynamic UART Configuration +-------------------------- +.. c:function:: w_status_t pps_configure_uart(uint8_t uart_module, uart_pin_config_t pin_config) + :param uart_module: UART module number (1-5) + :param pin_config: UART pin configuration structure :returns: Status code indicating success or failure :retval: ``W_SUCCESS`` if configuration was successful + :retval: ``W_INVALID_PARAM`` if module number or pin parameters are invalid + + Configure UART pins dynamically for the specified module. Sets up TX as output and RX + as input with appropriate PPS mappings. + + **Features:** - Configures I2C1 to use RC3 for SCL and RC4 for SDA. Since I2C is bidirectional, - both input and output mappings are configured for each pin. The pins are also set to - open-drain mode as required for I2C operation. + * Supports UART modules 1-5 + * Configures TX pin as output, RX pin as input + * Sets up proper PPS input and output mappings + * Validates module number and pin parameters -.. c:function:: static w_status_t pps_configure_spi1(void) +Dynamic PWM Configuration +------------------------- +.. c:function:: w_status_t pps_configure_pwm(uint8_t ccp_module, pwm_pin_config_t pin_config) + :param ccp_module: CCP module number (1-5) + :param pin_config: PWM pin configuration structure :returns: Status code indicating success or failure :retval: ``W_SUCCESS`` if configuration was successful + :retval: ``W_INVALID_PARAM`` if module number or pin parameters are invalid + + Configure PWM/CCP pins dynamically for the specified module. Sets up the output pin + direction and PPS mapping. This must be called before initializing the PWM module. + + **Features:** + + * Supports CCP modules 1-5 for PWM output + * Configures output pin direction and PPS mapping + * Must be called before PWM module initialization + * Validates module number and pin parameters + +Dynamic External Interrupt Configuration +---------------------------------------- +.. c:function:: w_status_t pps_configure_external_interrupt(uint8_t int_number, ext_int_pin_config_t pin_config) + + :param int_number: External interrupt number (0-2 for INT0, INT1, INT2) + :param pin_config: External interrupt pin configuration structure + :returns: Status code indicating success or failure + :retval: ``W_SUCCESS`` if configuration was successful + :retval: ``W_INVALID_PARAM`` if interrupt number or pin parameters are invalid + + Configure external interrupt pins dynamically for the specified interrupt. Sets up the + pin as a digital input and maps it to the interrupt input via PPS. - Configures the SPI1 module in master mode using: + **Features:** - * RB1 for SCK (output) - * RB2 for SDI (input) - * RB3 for SDO (output) + * Supports external interrupts INT0, INT1, and INT2 + * Configures pin as digital input + * Maps pin to interrupt input via PPS + * Validates interrupt number and pin parameters -.. c:function:: static w_status_t pps_configure_uart1(void) +Dynamic Timer Clock Configuration +--------------------------------- +.. c:function:: w_status_t pps_configure_timer_clk(uint8_t timer, pin_config_t pin_config) + :param timer: Timer number to configure (0-6) + :param pin_config: Pin configuration for the external clock input :returns: Status code indicating success or failure :retval: ``W_SUCCESS`` if configuration was successful + :retval: ``W_INVALID_PARAM`` if timer number or pin parameters are invalid + + Configure external clock input for the specified timer. Sets up the pin as a digital + input and maps it to the timer's external clock input via PPS. - Configures the UART1 module using: + **Features:** - * RC6 for TX (output) - * RC7 for RX (input) + * Supports Timer0 through Timer6 + * Configures pin as digital input for external clock + * Maps pin to timer clock input via PPS + * Validates timer number and pin parameters -.. c:function:: static w_status_t pps_configure_timer_clk(unsigned char timer, unsigned char port, unsigned char pin) +Dynamic Timer Gate Configuration +-------------------------------- +.. c:function:: w_status_t pps_configure_timer_gate(uint8_t timer, pin_config_t pin_config) - :param timer: Timer number to configure (0, 1, 3, 5) - :param port: Port number where clock input is located (0=PORTA, 1=PORTB, 2=PORTC) - :param pin: Pin number within the port (0-7) + :param timer: Timer number to configure (0-6) + :param pin_config: Pin configuration for the timer gate input :returns: Status code indicating success or failure :retval: ``W_SUCCESS`` if configuration was successful - :retval: ``W_INVALID_PARAM`` if timer, port, or pin parameters are invalid + :retval: ``W_INVALID_PARAM`` if timer number or pin parameters are invalid + + Configure timer gate input for the specified timer. Sets up the pin as a digital + input and maps it to the timer's gate input via PPS. - Configures an external clock input for the specified timer. This is not called by default - in the initialization routine but is available for applications that need external timer - clock sources. + **Features:** + + * Supports Timer0 through Timer6 + * Configures pin as digital input for gate control + * Maps pin to timer gate input via PPS + * Validates timer number and pin parameters + +Security and Safety Features +============================ + +PPS Lock Management +------------------- + +The module implements robust PPS register lock management to ensure system security: + +* **Automatic Lock/Unlock**: All configuration functions automatically handle PPS register unlocking and locking +* **Interrupt Safety**: PPS operations preserve the current interrupt state during critical sequences +* **Error Recovery**: If any configuration step fails, PPS registers are always locked before returning +* **Cleanup Pattern**: All functions use a consistent cleanup pattern with ``goto`` statements to ensure proper resource management + +Lock/Unlock Sequence +-------------------- + +The PPS lock/unlock mechanism follows these steps: + +1. **Save Interrupt State**: Current GIE (Global Interrupt Enable) state is preserved +2. **Disable Interrupts**: Interrupts are temporarily disabled during the critical sequence +3. **Unlock Sequence**: Write 0x55, then 0xAA to PPSLOCK register, then clear PPSLOCKED bit +4. **Configuration**: Perform the required pin and PPS configuration +5. **Lock Sequence**: Write 0x55, then 0xAA to PPSLOCK register, then set PPSLOCKED bit +6. **Restore Interrupts**: Original GIE state is restored -Usage Example -============= +**Security Benefits:** -The PPS configuration should be performed early in your application's initialization sequence: +* Prevents accidental PPS register modification +* Ensures atomic configuration operations +* Maintains interrupt context integrity +* Provides predictable behavior in all execution contexts + +Usage Examples +============== + +Basic Usage with Multiple Modules +---------------------------------- + +Example showing configuration of multiple peripheral modules: .. code-block:: c @@ -129,26 +313,325 @@ The PPS configuration should be performed early in your application's initializa // Initialize the microcontroller (clocks, etc.) mcu_init(); - // Configure PPS mapping for peripherals - w_status_t status = pin_init(); + // Configure I2C1 on RC3/RC4 + i2c_pin_config_t i2c1_config = { + .scl = {.port = 2, .pin = 3}, // RC3 + .sda = {.port = 2, .pin = 4} // RC4 + }; + w_status_t status = pps_configure_i2c(1, i2c1_config); + if (status != W_SUCCESS) { + // Handle error + return -1; + } + + // Configure I2C2 on different pins: RA1/RA2 + i2c_pin_config_t i2c2_config = { + .scl = {.port = 0, .pin = 1}, // RA1 + .sda = {.port = 0, .pin = 2} // RA2 + }; + status = pps_configure_i2c(2, i2c2_config); + if (status != W_SUCCESS) { + // Handle error + return -1; + } + + // Configure PWM on CCP1 using RB5 + pwm_pin_config_t pwm_config = { + .output = {.port = 1, .pin = 5} // RB5 + }; + status = pps_configure_pwm(1, pwm_config); + if (status != W_SUCCESS) { + // Handle error + return -1; + } + + // Configure UART1 on RC6/RC7 + uart_pin_config_t uart_config = { + .tx = {.port = 2, .pin = 6}, // RC6 + .rx = {.port = 2, .pin = 7} // RC7 + }; + status = pps_configure_uart(1, uart_config); + if (status != W_SUCCESS) { + // Handle error + return -1; + } + + // Configure external interrupt INT0 on RB0 + ext_int_pin_config_t int_config = { + .input = {.port = 1, .pin = 0} // RB0 + }; + status = pps_configure_external_interrupt(0, int_config); if (status != W_SUCCESS) { // Handle error + return -1; } - // Now initialize peripherals that depend on PPS configuration + // Now initialize peripherals (pin configuration is done) i2c_init(frequency_divider); - spi_init(mode, clock_polarity, clock_phase); - // ...other peripheral initializations... + pwm_init(1, pwm_period); // No pin config needed, already done + uart_init(baud_rate); while(1) { // Main application loop } } +Advanced SPI Configuration with Slave Select +-------------------------------------------- + +Example showing SPI configuration with optional slave select: + +.. code-block:: c + + // Configure SPI1 with slave select for external device control + spi_pin_config_t spi_config = { + .sck = {.port = 2, .pin = 0}, // RC0 - Serial Clock + .sdi = {.port = 2, .pin = 1}, // RC1 - Serial Data Input + .sdo = {.port = 2, .pin = 2}, // RC2 - Serial Data Output + .ss = {.port = 2, .pin = 5} // RC5 - Slave Select + }; + + // Configure with slave select enabled + w_status_t status = pps_configure_spi(1, spi_config, true); + if (status != W_SUCCESS) { + // Handle configuration error + return -1; + } + + // Initialize SPI peripheral after pin configuration + spi_init(); + +Modular Design Example +---------------------- + +Example showing separation of concerns: + +.. code-block:: c + + // In pin_setup.c - Centralized pin configuration + w_status_t setup_all_pins(void) { + w_status_t status; + + // Configure all I2C pins + i2c_pin_config_t i2c_config = { + .scl = {.port = 2, .pin = 3}, + .sda = {.port = 2, .pin = 4} + }; + status = pps_configure_i2c(1, i2c_config); + if (status != W_SUCCESS) return status; + + // Configure all PWM pins + pwm_pin_config_t pwm1_config = {.output = {.port = 1, .pin = 5}}; + status = pps_configure_pwm(1, pwm1_config); + if (status != W_SUCCESS) return status; + + pwm_pin_config_t pwm2_config = {.output = {.port = 1, .pin = 6}}; + status = pps_configure_pwm(2, pwm2_config); + if (status != W_SUCCESS) return status; + + // Configure SPI with slave select + spi_pin_config_t spi_config = { + .sck = {.port = 2, .pin = 0}, + .sdi = {.port = 2, .pin = 1}, + .sdo = {.port = 2, .pin = 2}, + .ss = {.port = 2, .pin = 5} + }; + status = pps_configure_spi(1, spi_config, true); + if (status != W_SUCCESS) return status; + + // Configure timer external clock + pin_config_t timer_clk = {.port = 1, .pin = 3}; + status = pps_configure_timer_clk(1, timer_clk); + if (status != W_SUCCESS) return status; + + return W_SUCCESS; + } + + // In main.c - Clean peripheral initialization + int main(void) { + mcu_init(); + + // Configure ALL pins first + if (setup_all_pins() != W_SUCCESS) { + // Handle error + return -1; + } + + // Then initialize peripherals (no pin concerns) + i2c_init(400000); // 400kHz I2C + pwm_init(1, 1000); // PWM1 with 1000 period + pwm_init(2, 2000); // PWM2 with 2000 period + spi_init(); // SPI master mode + + while(1) { + // Application logic + } + } + +Timer Configuration Example +--------------------------- + +Example showing timer external clock and gate configuration: + +.. code-block:: c + + // Configure Timer1 external clock on RB3 + pin_config_t timer1_clk = {.port = 1, .pin = 3}; // RB3 + w_status_t status = pps_configure_timer_clk(1, timer1_clk); + if (status != W_SUCCESS) { + // Handle error + return -1; + } + + // Configure Timer1 gate control on RB4 + pin_config_t timer1_gate = {.port = 1, .pin = 4}; // RB4 + status = pps_configure_timer_gate(1, timer1_gate); + if (status != W_SUCCESS) { + // Handle error + return -1; + } + + // Now initialize timer with external clock and gate + timer1_init_external_clock(); + +Implementation Details +====================== + +The PPS configuration module uses helper functions following BARR-C coding standards: + +Module Support +-------------- + +* **I2C**: Supports I2C1 and I2C2 modules with automatic open-drain configuration +* **SPI**: Supports SPI1 and SPI2 modules with optional slave select for master mode +* **UART**: Supports UART1 through UART5 modules with proper TX/RX configuration +* **PWM/CCP**: Supports CCP1 through CCP5 modules for PWM output +* **External Interrupts**: Supports INT0, INT1, and INT2 with proper input configuration +* **Timer**: Supports Timer0 through Timer6 external clock and gate inputs + +Helper Functions +---------------- + +All register access is done through proper functions (no function-like macros per BARR-C): + +**Register Access Functions:** +* ``get_tris_register()`` - Get TRIS register for port direction control +* ``get_ansel_register()`` - Get ANSEL register for analog/digital mode selection +* ``get_odcon_register()`` - Get ODCON register for open-drain configuration +* ``get_pps_output_register()`` - Get PPS output register for port/pin mapping + +**Configuration Functions:** +* ``configure_pin_digital()`` - Configure pin for digital I/O with direction setting +* ``configure_pin_open_drain()`` - Configure pin for open-drain mode (I2C) +* ``configure_pps_output()`` - Configure PPS output mapping for peripherals +* ``validate_pin_config()`` - Validate pin configuration parameters + +**PPS Management Functions:** +* ``pps_unlock()`` - Safely unlock PPS registers with interrupt state preservation +* ``pps_lock()`` - Safely lock PPS registers with interrupt state restoration + +PPS Codes +--------- + +The module defines peripheral codes for PPS configuration: + +**I2C Output Codes:** +* ``PPS_I2C1_SCL_OUTPUT``: 0b100001 - I2C1 Serial Clock output +* ``PPS_I2C1_SDA_OUTPUT``: 0b100010 - I2C1 Serial Data output +* ``PPS_I2C2_SCL_OUTPUT``: 0b100011 - I2C2 Serial Clock output +* ``PPS_I2C2_SDA_OUTPUT``: 0b100100 - I2C2 Serial Data output + +**SPI Output Codes:** +* ``PPS_SPI1_SCK_OUTPUT``: 0b011110 - SPI1 Serial Clock output +* ``PPS_SPI1_SDO_OUTPUT``: 0b011111 - SPI1 Serial Data Output +* ``PPS_SPI2_SCK_OUTPUT``: 0b100000 - SPI2 Serial Clock output +* ``PPS_SPI2_SDO_OUTPUT``: 0b100001 - SPI2 Serial Data Output + +**UART Output Codes:** +* ``PPS_UART1_TX_OUTPUT``: 0b010011 - UART1 Transmit output +* ``PPS_UART2_TX_OUTPUT``: 0b010100 - UART2 Transmit output +* ``PPS_UART3_TX_OUTPUT``: 0b010101 - UART3 Transmit output +* ``PPS_UART4_TX_OUTPUT``: 0b010110 - UART4 Transmit output +* ``PPS_UART5_TX_OUTPUT``: 0b010111 - UART5 Transmit output + +**PWM/CCP Output Codes:** +* ``PPS_CCP1_OUTPUT``: 0b001100 - CCP1/PWM1 output +* ``PPS_CCP2_OUTPUT``: 0b001101 - CCP2/PWM2 output +* ``PPS_CCP3_OUTPUT``: 0b001110 - CCP3/PWM3 output +* ``PPS_CCP4_OUTPUT``: 0b001111 - CCP4/PWM4 output +* ``PPS_CCP5_OUTPUT``: 0b010000 - CCP5/PWM5 output + +Error Handling and Recovery +--------------------------- + +The implementation provides comprehensive error handling: + +**Parameter Validation:** +* Module number range checking (e.g., I2C: 1-2, UART: 1-5, CCP: 1-5) +* Port number validation (0-2 for PORTA-PORTC) +* Pin number validation (0-7 for each port) + +**Error Recovery:** +* Cleanup pattern ensures PPS registers are always locked +* All functions use ``goto cleanup`` for error paths after PPS unlock +* Original interrupt state is always restored +* Failed operations leave system in consistent state + +**Error Codes:** +* ``W_SUCCESS`` - Operation completed successfully +* ``W_INVALID_PARAM`` - Invalid module number, port, or pin parameter + +Architecture and Design Principles +================================== + +Separation of Concerns +---------------------- + +The pin configuration module follows strict separation of concerns: + +* **Pin Configuration Layer**: Handles all pin-related setup (direction, mode, PPS mapping) +* **Peripheral Layers**: Focus solely on peripheral functionality and register configuration +* **Application Layer**: Uses both layers independently with clear interfaces + +This design provides several benefits: + +* **Modularity**: Each module has a single, well-defined responsibility +* **Testability**: Pin configuration can be tested independently of peripheral logic +* **Flexibility**: Pin mappings can be changed without modifying peripheral code +* **Maintainability**: Clear boundaries make code easier to understand and modify + + +Thread Safety and Interrupt Handling +------------------------------------ + +The module provides robust interrupt safety: + +* **Interrupt State Preservation**: Current GIE state is saved and restored +* **Atomic Operations**: PPS configuration is atomic with respect to interrupts +* **Critical Section Management**: Minimal time spent with interrupts disabled +* **Predictable Behavior**: Safe to call from interrupt context or initialization code + +Best Practices +============== + +Configuration Order +------------------- + +Follow this recommended order for system initialization: + +1. **MCU Initialization**: Set up clocks, power management +2. **Pin Configuration**: Configure all peripheral pins using this module +3. **Peripheral Initialization**: Initialize peripheral modules +4. **Application Logic**: Start main application functionality + Notes ===== -* The actual pin assignments can be modified in the `pin_config.c` file if different pins are required. -* PWM/CCP pin assignments should be configured through the PWM module's own initialization function. -* When switching between peripherals that share the same pins (e.g., SPI and I2C on the same MSSP module), - the PPS configuration must be updated accordingly. \ No newline at end of file +* **Separation of Concerns**: Pin configuration is handled entirely by this module +* **Module Independence**: PWM, I2C, SPI, UART modules focus only on their functionality +* **Multiple Module Support**: Supports multiple instances of peripherals where available +* **Parameter Validation**: All functions validate module numbers and pin parameters +* **Error Handling**: Returns appropriate error codes for invalid configurations +* **Security**: Robust PPS lock management prevents accidental register modification +* **Interrupt Safety**: Preserves interrupt state during critical PPS sequences +* **Resource Management**: Automatic cleanup ensures system consistency \ No newline at end of file diff --git a/include/pin_config.h b/include/pin_config.h index 3752fd0..2054e9b 100644 --- a/include/pin_config.h +++ b/include/pin_config.h @@ -2,13 +2,13 @@ #define ROCKETLIB_PIN_CONFIG_H #include "common.h" -#include #include +#include // Structure to hold pin configuration details typedef struct { uint8_t port; // Port number (0=A, 1=B, 2=C) - uint8_t pin; // Pin number (0-7) + uint8_t pin; // Pin number (0-7) } pin_config_t; // Structure for I2C pin configuration @@ -22,7 +22,7 @@ typedef struct { pin_config_t sck; // Clock pin configuration pin_config_t sdi; // Data input pin configuration pin_config_t sdo; // Data output pin configuration - pin_config_t ss; // Slave select pin configuration (optional) + pin_config_t ss; // Slave select pin configuration (optional) } spi_pin_config_t; // Structure for UART pin configuration diff --git a/pic18f26k83/pin_config.c b/pic18f26k83/pin_config.c index 8cdb63c..650d813 100644 --- a/pic18f26k83/pin_config.c +++ b/pic18f26k83/pin_config.c @@ -31,78 +31,117 @@ static w_status_t pps_lock(void) { /** * @brief Get TRIS register address for the specified port */ -static volatile uint8_t* get_tris_register(uint8_t port) { +static volatile uint8_t *get_tris_register(uint8_t port) { switch (port) { - case 0U: return &TRISA; - case 1U: return &TRISB; - case 2U: return &TRISC; - default: return NULL; + case 0U: + return &TRISA; + case 1U: + return &TRISB; + case 2U: + return &TRISC; + default: + return NULL; } } /** * @brief Get ANSEL register address for the specified port */ -static volatile uint8_t* get_ansel_register(uint8_t port) { +static volatile uint8_t *get_ansel_register(uint8_t port) { switch (port) { - case 0U: return &ANSELA; - case 1U: return &ANSELB; - case 2U: return &ANSELC; - default: return NULL; + case 0U: + return &ANSELA; + case 1U: + return &ANSELB; + case 2U: + return &ANSELC; + default: + return NULL; } } /** * @brief Get ODCON register address for the specified port */ -static volatile uint8_t* get_odcon_register(uint8_t port) { +static volatile uint8_t *get_odcon_register(uint8_t port) { switch (port) { - case 0U: return &ODCONA; - case 1U: return &ODCONB; - case 2U: return &ODCONC; - default: return NULL; + case 0U: + return &ODCONA; + case 1U: + return &ODCONB; + case 2U: + return &ODCONC; + default: + return NULL; } } /** * @brief Get PPS output register address for the specified port and pin */ -static volatile uint8_t* get_pps_output_register(uint8_t port, uint8_t pin) { +static volatile uint8_t *get_pps_output_register(uint8_t port, uint8_t pin) { if (port == 0U) { // PORTA switch (pin) { - case 0U: return &RA0PPS; - case 1U: return &RA1PPS; - case 2U: return &RA2PPS; - case 3U: return &RA3PPS; - case 4U: return &RA4PPS; - case 5U: return &RA5PPS; - case 6U: return &RA6PPS; - case 7U: return &RA7PPS; - default: return NULL; + case 0U: + return &RA0PPS; + case 1U: + return &RA1PPS; + case 2U: + return &RA2PPS; + case 3U: + return &RA3PPS; + case 4U: + return &RA4PPS; + case 5U: + return &RA5PPS; + case 6U: + return &RA6PPS; + case 7U: + return &RA7PPS; + default: + return NULL; } } else if (port == 1U) { // PORTB switch (pin) { - case 0U: return &RB0PPS; - case 1U: return &RB1PPS; - case 2U: return &RB2PPS; - case 3U: return &RB3PPS; - case 4U: return &RB4PPS; - case 5U: return &RB5PPS; - case 6U: return &RB6PPS; - case 7U: return &RB7PPS; - default: return NULL; + case 0U: + return &RB0PPS; + case 1U: + return &RB1PPS; + case 2U: + return &RB2PPS; + case 3U: + return &RB3PPS; + case 4U: + return &RB4PPS; + case 5U: + return &RB5PPS; + case 6U: + return &RB6PPS; + case 7U: + return &RB7PPS; + default: + return NULL; } } else if (port == 2U) { // PORTC switch (pin) { - case 0U: return &RC0PPS; - case 1U: return &RC1PPS; - case 2U: return &RC2PPS; - case 3U: return &RC3PPS; - case 4U: return &RC4PPS; - case 5U: return &RC5PPS; - case 6U: return &RC6PPS; - case 7U: return &RC7PPS; - default: return NULL; + case 0U: + return &RC0PPS; + case 1U: + return &RC1PPS; + case 2U: + return &RC2PPS; + case 3U: + return &RC3PPS; + case 4U: + return &RC4PPS; + case 5U: + return &RC5PPS; + case 6U: + return &RC6PPS; + case 7U: + return &RC7PPS; + default: + return NULL; } } return NULL; @@ -363,51 +402,51 @@ w_status_t pps_configure_i2c(uint8_t i2c_module, i2c_pin_config_t pin_config) { // Unlock PPS registers status = pps_unlock(); - if (status != W_SUCCESS) { - return status; + if (status != W_SUCCESS) { + return status; } // Configure SCL pin status = configure_pin_digital(pin_config.scl, 1U); // Input initially - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } status = configure_pin_open_drain(pin_config.scl); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure SDA pin status = configure_pin_digital(pin_config.sda, 1U); // Input initially - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } status = configure_pin_open_drain(pin_config.sda); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure PPS input mappings status = configure_i2c_input_pps(i2c_module, pin_config); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure PPS output mappings status = configure_pps_output(pin_config.scl, scl_pps_code); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } status = configure_pps_output(pin_config.sda, sda_pps_code); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } cleanup: @@ -434,57 +473,57 @@ w_status_t pps_configure_spi(uint8_t spi_module, spi_pin_config_t pin_config, bo // Unlock PPS registers status = pps_unlock(); - if (status != W_SUCCESS) { - return status; + if (status != W_SUCCESS) { + return status; } // Configure SCK pin (output for master mode) status = configure_pin_digital(pin_config.sck, 0U); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure SDI pin (input for master mode) status = configure_pin_digital(pin_config.sdi, 1U); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure SDO pin (output for master mode) status = configure_pin_digital(pin_config.sdo, 0U); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure SS pin if requested (output for master mode) if (use_ss) { status = configure_pin_digital(pin_config.ss, 0U); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } } // Configure PPS input mappings status = configure_spi_input_pps(spi_module, pin_config); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure PPS output mappings status = configure_pps_output(pin_config.sck, sck_pps_code); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } status = configure_pps_output(pin_config.sdo, sdo_pps_code); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } cleanup: @@ -511,36 +550,36 @@ w_status_t pps_configure_uart(uint8_t uart_module, uart_pin_config_t pin_config) // Unlock PPS registers status = pps_unlock(); - if (status != W_SUCCESS) { - return status; + if (status != W_SUCCESS) { + return status; } // Configure TX pin (output) status = configure_pin_digital(pin_config.tx, 0U); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure RX pin (input) status = configure_pin_digital(pin_config.rx, 1U); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure PPS input mapping status = configure_uart_input_pps(uart_module, pin_config.rx); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure PPS output mapping status = configure_pps_output(pin_config.tx, tx_pps_code); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } cleanup: @@ -567,22 +606,22 @@ w_status_t pps_configure_pwm(uint8_t ccp_module, pwm_pin_config_t pin_config) { // Unlock PPS registers status = pps_unlock(); - if (status != W_SUCCESS) { - return status; + if (status != W_SUCCESS) { + return status; } // Configure output pin (PWM output) status = configure_pin_digital(pin_config.output, 0U); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure PPS output mapping status = configure_pps_output(pin_config.output, pps_code); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } cleanup: @@ -602,15 +641,15 @@ w_status_t pps_configure_external_interrupt(uint8_t int_number, ext_int_pin_conf // Unlock PPS registers status = pps_unlock(); - if (status != W_SUCCESS) { - return status; + if (status != W_SUCCESS) { + return status; } // Configure pin as digital input status = configure_pin_digital(pin_config.input, 1U); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure PPS input mapping based on interrupt number @@ -647,15 +686,15 @@ w_status_t pps_configure_timer_clk(uint8_t timer, pin_config_t pin_config) { // Unlock PPS registers status = pps_unlock(); - if (status != W_SUCCESS) { - return status; + if (status != W_SUCCESS) { + return status; } // Configure pin as digital input status = configure_pin_digital(pin_config, 1U); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure PPS input mapping based on timer @@ -704,15 +743,15 @@ w_status_t pps_configure_timer_gate(uint8_t timer, pin_config_t pin_config) { // Unlock PPS registers status = pps_unlock(); - if (status != W_SUCCESS) { - return status; + if (status != W_SUCCESS) { + return status; } // Configure pin as digital input status = configure_pin_digital(pin_config, 1U); - if (status != W_SUCCESS) { + if (status != W_SUCCESS) { final_status = status; - goto cleanup; + goto cleanup; } // Configure PPS input mapping for timer gate diff --git a/pic18f26k83/pwm.c b/pic18f26k83/pwm.c index d035bfe..6e0d8c0 100644 --- a/pic18f26k83/pwm.c +++ b/pic18f26k83/pwm.c @@ -4,42 +4,60 @@ /** * @brief Get CCPR Low register address for the specified CCP module */ -static volatile uint8_t* get_ccpr_low_register(uint8_t ccp_module) { +static volatile uint8_t *get_ccpr_low_register(uint8_t ccp_module) { switch (ccp_module) { - case 1U: return &CCPR1L; - case 2U: return &CCPR2L; - case 3U: return &CCPR3L; - case 4U: return &CCPR4L; - case 5U: return &CCPR5L; - default: return NULL; + case 1U: + return &CCPR1L; + case 2U: + return &CCPR2L; + case 3U: + return &CCPR3L; + case 4U: + return &CCPR4L; + case 5U: + return &CCPR5L; + default: + return NULL; } } /** * @brief Get CCPR High register address for the specified CCP module */ -static volatile uint8_t* get_ccpr_high_register(uint8_t ccp_module) { +static volatile uint8_t *get_ccpr_high_register(uint8_t ccp_module) { switch (ccp_module) { - case 1U: return &CCPR1H; - case 2U: return &CCPR2H; - case 3U: return &CCPR3H; - case 4U: return &CCPR4H; - case 5U: return &CCPR5H; - default: return NULL; + case 1U: + return &CCPR1H; + case 2U: + return &CCPR2H; + case 3U: + return &CCPR3H; + case 4U: + return &CCPR4H; + case 5U: + return &CCPR5H; + default: + return NULL; } } /** * @brief Get CCPxCON register address for the specified CCP module */ -static volatile uint8_t* get_ccp_con_register(uint8_t ccp_module) { +static volatile uint8_t *get_ccp_con_register(uint8_t ccp_module) { switch (ccp_module) { - case 1U: return &CCP1CON; - case 2U: return &CCP2CON; - case 3U: return &CCP3CON; - case 4U: return &CCP4CON; - case 5U: return &CCP5CON; - default: return NULL; + case 1U: + return &CCP1CON; + case 2U: + return &CCP2CON; + case 3U: + return &CCP3CON; + case 4U: + return &CCP4CON; + case 5U: + return &CCP5CON; + default: + return NULL; } } From 8dc9e845a20190d7d5057d19696d4fac8f16fb9a Mon Sep 17 00:00:00 2001 From: taisirhassan Date: Sat, 31 May 2025 03:58:47 -0400 Subject: [PATCH 9/9] Update GPIO, I2C, PWM, and SPI driver documentation with detailed usage examples and enhanced structure descriptions --- doc/gpio_driver.rst | 318 +++++++++++++++++++++++++++++++++---- doc/i2c_driver.rst | 291 +++++++++++++++++++++++++++------- doc/pwm_driver.rst | 146 +++++------------ doc/spi_driver.rst | 371 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 909 insertions(+), 217 deletions(-) diff --git a/doc/gpio_driver.rst b/doc/gpio_driver.rst index 50d84d7..4ab2307 100644 --- a/doc/gpio_driver.rst +++ b/doc/gpio_driver.rst @@ -1,46 +1,304 @@ -GPIO Driver (Not Implemented) -***************************** +GPIO Driver +*********** -Macros -====== +The GPIO driver provides basic digital input/output functionality for the PIC18F26K83. This driver focuses on high-level GPIO operations, while the underlying pin configuration (direction, digital/analog mode, PPS mapping) is handled by the dedicated pin configuration module. -Output enable -------------- -.. c:macro:: gpio_enable_output(port, pin) +**Key Features:** - Initialize a GPIO pin to be used as digital output. +* Simple digital I/O macros for performance-critical operations +* Support for all available GPIO pins (PORTA, PORTB, PORTC) +* Macro-based implementation for zero runtime overhead +* Separation of concerns: pin mode configuration handled separately - :param port: MCU port, a letter e.g. A, B - :param pin: Pin number +**Current Status:** Interface defined, implementation pending -Input enable ------------- -.. c:macro:: gpio_enable_input(port, pin) +Relationship with Pin Configuration +==================================== + +The GPIO driver operates at a higher level than the pin configuration module: + +* **Pin Configuration Module**: Handles pin direction (TRIS), digital/analog mode (ANSEL), and PPS routing +* **GPIO Driver**: Provides convenient macros for reading/writing pin values after configuration + +**Setup Sequence:** + +1. Configure pin using pin configuration module functions +2. Use GPIO macros for fast I/O operations - Initialize a GPIO pin to be used as digital input. +.. code-block:: c - :param port: MCU port, a letter e.g. A, B - :param pin: Pin number + // Step 1: Configure pin for digital output (done once) + pin_config_t led_pin = {.port = 1, .pin = 5}; // RB5 + configure_pin_digital(led_pin, 0); // 0 = output + + // Step 2: Use GPIO macros for fast operations (done repeatedly) + gpio_set_output(B, 5, 1); // Turn on LED + gpio_set_output(B, 5, 0); // Turn off LED + +GPIO Macros +=========== + +Output Control +-------------- +.. c:macro:: gpio_enable_output(port, pin) + + Initialize a GPIO pin for digital output operation. + + :param port: MCU port letter (A, B, or C) + :param pin: Pin number (0-7) + + **Example:** + + .. code-block:: c + + gpio_enable_output(B, 5); // Configure RB5 as output -Set output value ----------------- .. c:macro:: gpio_set_output(port, pin, value) - Set a GPIO digital output pin to output a value. + Set a GPIO digital output pin to the specified value. + + :param port: MCU port letter (A, B, or C) + :param pin: Pin number (0-7) + :param value: Output value (0 = low, 1 = high) + + **Example:** + + .. code-block:: c + + gpio_set_output(C, 2, 1); // Set RC2 high + gpio_set_output(C, 2, 0); // Set RC2 low - :param port: MCU port, a letter e.g. A, B - :param pin: Pin number - :param value: Value to be set +Input Control +------------- +.. c:macro:: gpio_enable_input(port, pin) + + Initialize a GPIO pin for digital input operation. + + :param port: MCU port letter (A, B, or C) + :param pin: Pin number (0-7) + + **Example:** + + .. code-block:: c + + gpio_enable_input(A, 3); // Configure RA3 as input -Read input value ----------------- .. c:macro:: gpio_get_input(port, pin) - Read digital input from a pin. + Read the current state of a digital input pin. + + :param port: MCU port letter (A, B, or C) + :param pin: Pin number (0-7) + :returns: Pin state (0 = low, 1 = high) + + **Example:** + + .. code-block:: c + + if (gpio_get_input(A, 0)) { + // RA0 is high + } + +Usage Examples +============== + +Basic GPIO Operations +--------------------- + +.. code-block:: c + + #include "gpio.h" + + int main(void) { + // Initialize MCU + mcu_init(); + + // Configure LED output + gpio_enable_output(B, 5); // RB5 as LED output + + // Configure button input + gpio_enable_input(A, 0); // RA0 as button input + + while(1) { + // Read button state and control LED + if (gpio_get_input(A, 0)) { + gpio_set_output(B, 5, 1); // Button pressed, LED on + } else { + gpio_set_output(B, 5, 0); // Button not pressed, LED off + } + } + } + +Integration with Pin Configuration Module +------------------------------------------ + +For more complex scenarios requiring PPS routing or special pin configurations: + +.. code-block:: c + + #include "pin_config.h" + #include "gpio.h" + + int main(void) { + mcu_init(); + + // Complex example: Configure pins for various functions + + // 1. Regular GPIO (no PPS needed) + gpio_enable_output(C, 0); // Simple LED + gpio_enable_input(A, 1); // Simple button + + // 2. Pins that need PPS configuration first + // Configure PWM output pin, then use as GPIO if needed + pwm_pin_config_t pwm_config = { + .output = {.port = 1, .pin = 6} // RB6 + }; + pps_configure_pwm(1, pwm_config); + // Now RB6 is configured for PWM, but could be used as GPIO too + + // 3. External interrupt pins + ext_int_pin_config_t int_config = { + .input = {.port = 1, .pin = 0} // RB0 + }; + pps_configure_external_interrupt(0, int_config); + // RB0 is now configured for INT0, hardware handles the input + + while(1) { + // Simple GPIO operations + gpio_set_output(C, 0, 1); + delay_ms(500); + gpio_set_output(C, 0, 0); + delay_ms(500); + } + } + +Blinking LED Example +--------------------- + +.. code-block:: c + + #include "gpio.h" + #include "millis.h" + + #define LED_PORT C + #define LED_PIN 2 + #define BLINK_INTERVAL_MS 1000 + + int main(void) { + mcu_init(); + timer0_init(); // For millis() function + + // Configure LED pin + gpio_enable_output(LED_PORT, LED_PIN); + + uint32_t last_toggle = 0; + uint8_t led_state = 0; + + while(1) { + uint32_t current_time = millis(); + + if (current_time - last_toggle >= BLINK_INTERVAL_MS) { + led_state = !led_state; + gpio_set_output(LED_PORT, LED_PIN, led_state); + last_toggle = current_time; + } + } + } + +Design Rationale +================ + +Why Macros? +----------- + +The GPIO driver uses macros instead of functions for performance reasons: + +**Performance Benefits:** +* **Zero Runtime Overhead**: Macros expand to direct register operations +* **Compile-time Optimization**: Port and pin selections resolved at compile time +* **Optimal Code Generation**: Single instruction operations where possible + +**Example Expansion:** + +.. code-block:: c + + // This macro call: + gpio_set_output(B, 3, 1); + + // Expands to something like: + PORTBbits.RB3 = 1; + + // Which generates a single assembly instruction + +**Alternative Approaches:** + +Function-based GPIO would require runtime overhead: + +.. code-block:: c + + // Hypothetical function call: + gpio_set_pin(GPIO_PORTB, 3, 1); + + // Would require: + // - Function call overhead + // - Parameter passing + // - Runtime port/pin selection logic + // - Multiple assembly instructions + +Macro Parameter Format +----------------------- + +The macro parameters use port letters (A, B, C) rather than numbers for clarity: + +* **More Readable**: ``gpio_set_output(B, 5, 1)`` vs ``gpio_set_output(1, 5, 1)`` +* **Hardware Correlation**: Matches datasheet naming (RB5, RC2, etc.) +* **Compile-time Validation**: Invalid port letters cause immediate compile errors + +Architecture Integration +========================= + +Layer Responsibilities +----------------------- + +.. code-block:: text + + Application Layer + | + +-----v-----+ + | GPIO | <- High-level I/O operations + | Driver | + +-----------+ + | + +-----v-----+ + | Pin | <- Pin configuration and PPS routing + | Config | + +-----------+ + | + +-----v-----+ + | Hardware | <- Register-level operations + | Registers | + +-----------+ + +**Clear Separation:** +* **GPIO Driver**: Fast I/O operations for application logic +* **Pin Config**: One-time setup of pin modes and routing +* **Hardware Layer**: Direct register manipulation + +Implementation Status +====================== + +**Current Status:** Interface defined, implementation pending + +**Planned Implementation:** +The macros will be implemented to generate optimal assembly code for each supported port and pin combination. - :param port: MCU port, a letter e.g. A, B - :param pin: Pin number +**Future Enhancements:** +* Port-wide operations (read/write entire ports) +* Atomic bit manipulation functions +* Pin change interrupt integration +* Pull-up/pull-down configuration support -Why Macros -========== -We want to pass which pin we are operating on without performance penalty. If we use a macro, it can just take for example ``A,3`` as a parameter and use it to generate C register write to the register. +**Integration Notes:** +* Designed to work seamlessly with the pin configuration module +* Compatible with all PPS-routed peripherals +* Suitable for both simple GPIO and complex mixed-mode applications diff --git a/doc/i2c_driver.rst b/doc/i2c_driver.rst index e15bcf5..813a6ef 100644 --- a/doc/i2c_driver.rst +++ b/doc/i2c_driver.rst @@ -1,86 +1,267 @@ -I2C Master Driver (Not Working) -******************************* +I2C Master Driver +****************** -The driver only handles when the device is used as an I2C master, because it's unlikely the MCU is going to used as an I2C slave on the rocket. Functions for reading 8 and 16 bit registers are provided. +The I2C driver provides master-only communication functionality for the PIC18F26K83. The driver focuses purely on I2C protocol implementation, while pin configuration is handled separately by the dedicated pin configuration module. -Assumptions in this revision -============================ -- I2C Address(exclude R/W bits) are 7 bits -- Only one I2C controller could be used -- Register address are 8 bit wide. +**Key Features:** + +* Master-only operation (slave mode not supported) +* Support for I2C1 and I2C2 modules +* 8-bit and 16-bit register access functions +* 7-bit addressing support +* Separation of concerns: pin configuration handled separately + +**Current Status:** Under development + +Prerequisites +============= + +Before using the I2C driver, you must configure the I2C pins using the pin configuration module: + +.. code-block:: c + + // Configure I2C1 pins first + i2c_pin_config_t i2c_config = { + .scl = {.port = 2, .pin = 3}, // RC3 for SCL + .sda = {.port = 2, .pin = 4} // RC4 for SDA + }; + w_status_t status = pps_configure_i2c(1, i2c_config); + if (status != W_SUCCESS) { + // Handle configuration error + return -1; + } + + // Then initialize I2C module + i2c_init(freq_divider); + +For details on I2C pin configuration, see the :doc:`pin_config` documentation. + +Design Assumptions +================== + +The current I2C driver implementation is based on these assumptions: + +* **Master Mode Only**: The MCU operates as I2C master since slave operation is unlikely in rocket applications +* **7-bit Addressing**: I2C device addresses are 7 bits (excluding R/W bit) +* **Single Controller**: Only one I2C controller is used at a time (though hardware supports I2C1 and I2C2) +* **8-bit Register Addresses**: Device register addresses are limited to 8 bits I2C Controller Functions ======================== +Initialization +-------------- .. c:function:: void i2c_init(uint8_t freq_div) - Initialize I2C module and set up pins + Initialize I2C module for master mode operation. + + :param freq_div: Frequency divider for I2C clock. I2C Frequency = 100 kHz / freq_div + :type freq_div: uint8_t + + .. note:: + Pin configuration must be completed using :c:func:`pps_configure_i2c` before calling this function. - :param uint8_t freq_div: frequency divider, I2C Frequency = 100 kHz / freq_div +Data Transfer Functions +----------------------- .. c:function:: bool i2c_write_data(uint8_t i2c_addr, const uint8_t *data, uint8_t len) - Send data through I2C, this is usually used for sending register address and write data. + Send data through I2C. Typically used for sending register addresses and write data. - :param uint8_t i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the RW bit - :param const uint8_t* data: data to be transmitted - :param uint8_t len: length of data to be transmitted in bytes, the I2C address byte is not included - :return: success or not - :retval true: success - :retval false: failed + :param i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the R/W bit + :type i2c_addr: uint8_t + :param data: Data to be transmitted + :type data: const uint8_t* + :param len: Length of data to be transmitted in bytes (I2C address byte not included) + :type len: uint8_t + :returns: Transfer status + :retval true: Success + :retval false: Failed + :rtype: bool .. c:function:: bool i2c_read_data(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *data, uint8_t len) - Receive data through I2C, this is usually used for receiving read data. + Receive data through I2C. Typically used for reading register data. + + :param i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the R/W bit + :type i2c_addr: uint8_t + :param reg_addr: Device register address (8 bits max) + :type reg_addr: uint8_t + :param data: Buffer for received data + :type data: uint8_t* + :param len: Length of data to be received in bytes + :type len: uint8_t + :returns: Transfer status + :retval true: Success + :retval false: Failed + :rtype: bool + +Register Access Functions +------------------------- - :param uint8_t i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the RW bit - :param uint8_t reg_addr: device register map address, max 8 bits wide - :param uint8_t* data: buffer for received data - :param uint8_t len: length of data to be received in bytes - :return: success or not - :retval true: success - :retval false: failed +8-bit Register Functions +~~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: bool i2c_read_reg8(uint8_t i2c_addr, uint8_t reg_addr, uint8_t* value) - Read a byte-wide device register + Read a byte-wide device register. - :param uint8_t i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the RW bit - :param uint8_t reg_addr: device register map address, max 8 bits wide - :param uint8_t* value: pointer to register value buffer - :return: success or not - :retval true: success - :retval false: failed + :param i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the R/W bit + :type i2c_addr: uint8_t + :param reg_addr: Device register address (8 bits max) + :type reg_addr: uint8_t + :param value: Pointer to register value buffer + :type value: uint8_t* + :returns: Operation status + :retval true: Success + :retval false: Failed + :rtype: bool -.. c:function:: bool i2c_read_reg16(uint8_t i2c_addr, uint8_t reg_addr, uint16_t* value) +.. c:function:: bool i2c_write_reg8(uint8_t i2c_addr, uint8_t reg_addr, uint8_t value) - Read a 2-byte device register + Write a byte-wide device register. - :param uint8_t i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the RW bit - :param uint8_t reg_addr: device register map address, max 8 bits wide - :param uint16_t* value: pointer to register value buffer - :return: success or not - :retval true: success - :retval false: failed + :param i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the R/W bit + :type i2c_addr: uint8_t + :param reg_addr: Device register address (8 bits max) + :type reg_addr: uint8_t + :param value: Value to be written to the register + :type value: uint8_t + :returns: Operation status + :retval true: Success + :retval false: Failed + :rtype: bool -.. c:function:: bool i2c_write_reg8(uint8_t i2c_addr, uint8_t reg_addr, uint8_t value) +16-bit Register Functions +~~~~~~~~~~~~~~~~~~~~~~~~~ - Write a byte-wide device register +.. c:function:: bool i2c_read_reg16(uint8_t i2c_addr, uint8_t reg_addr, uint16_t* value) - :param uint8_t i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the RW bit - :param uint8_t reg_addr: device register map address, max 8 bits wide - :param uint8_t value: value to be written to the register - :return: success or not - :retval true: success - :retval false: failed + Read a 2-byte device register. + + :param i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the R/W bit + :type i2c_addr: uint8_t + :param reg_addr: Device register address (8 bits max) + :type reg_addr: uint8_t + :param value: Pointer to register value buffer + :type value: uint16_t* + :returns: Operation status + :retval true: Success + :retval false: Failed + :rtype: bool .. c:function:: bool i2c_write_reg16(uint8_t i2c_addr, uint8_t reg_addr, uint16_t value) - Write a 2-byte device register + Write a 2-byte device register. + + :param i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the R/W bit + :type i2c_addr: uint8_t + :param reg_addr: Device register address (8 bits max) + :type reg_addr: uint8_t + :param value: Value to be written to the register + :type value: uint16_t + :returns: Operation status + :retval true: Success + :retval false: Failed + :rtype: bool + +Usage Example +============= + +Complete I2C Setup and Usage +---------------------------- + +.. code-block:: c + + #include "pin_config.h" + #include "i2c.h" + + int main(void) { + // Initialize MCU + mcu_init(); + + // Configure I2C1 pins + i2c_pin_config_t i2c_config = { + .scl = {.port = 2, .pin = 3}, // RC3 + .sda = {.port = 2, .pin = 4} // RC4 + }; + + w_status_t status = pps_configure_i2c(1, i2c_config); + if (status != W_SUCCESS) { + // Handle pin configuration error + return -1; + } + + // Initialize I2C at 400kHz (100kHz / 0.25) + i2c_init(1); // freq_div = 1 for ~100kHz, adjust as needed + + // Example: Read from a sensor + uint8_t sensor_addr = 0x48; // 7-bit address (will be shifted for R/W) + uint8_t reg_addr = 0x00; // Temperature register + uint16_t temperature; + + if (i2c_read_reg16(sensor_addr, reg_addr, &temperature)) { + // Successfully read temperature + // Process temperature data + } else { + // Handle I2C communication error + } + + while(1) { + // Main application loop + } + } + +Device Communication Pattern +----------------------------- + +.. code-block:: c + + // Example: Configure a device register + uint8_t device_addr = 0x1D; // Accelerometer address + uint8_t config_reg = 0x20; // Control register + uint8_t config_val = 0x47; // Enable XYZ axes, 50Hz + + if (!i2c_write_reg8(device_addr, config_reg, config_val)) { + // Handle write error + } + + // Read acceleration data + uint8_t accel_data[6]; + if (i2c_read_data(device_addr, 0x28, accel_data, 6)) { + // Process XYZ acceleration data + int16_t accel_x = (accel_data[1] << 8) | accel_data[0]; + int16_t accel_y = (accel_data[3] << 8) | accel_data[2]; + int16_t accel_z = (accel_data[5] << 8) | accel_data[4]; + } + +Architecture Notes +================== + +**Separation of Concerns:** +* Pin configuration is handled by the pin configuration module +* I2C driver focuses solely on protocol implementation +* Clean interfaces between modules enable independent testing and development + +**Multi-Module Support:** +While the current implementation assumes single controller usage, the hardware supports both I2C1 and I2C2. Future enhancements could extend the API to support multiple simultaneous I2C controllers. + +**Error Handling:** +Functions return boolean status codes. Consider implementing more detailed error reporting in future revisions for better debugging and fault diagnosis. + +Implementation Status +====================== + +**Current Status:** Under development + +**Limitations:** +* Single I2C controller support (hardware supports I2C1 and I2C2) +* 8-bit register address limitation +* Boolean-only error reporting - :param uint8_t i2c_addr: I2C peripheral address, where addr[7:1] is the 7-bit address, and addr[0] is the RW bit - :param uint8_t reg_addr: device register map address, max 8 bits wide - :param uint16_t value: value to be written to the register - :return: success or not - :retval true: success - :retval false: failed +**Future Enhancements:** +* Multi-controller support +* Extended register address support (16-bit) +* Detailed error codes +* Interrupt-driven operation +* DMA support for bulk transfers diff --git a/doc/pwm_driver.rst b/doc/pwm_driver.rst index d033ff6..33eccf2 100644 --- a/doc/pwm_driver.rst +++ b/doc/pwm_driver.rst @@ -1,119 +1,63 @@ PIC18 PWM Driver **************** -The driver provides PWM output functionality for the PIC18F26K83 using the CCP (Capture/Compare/PWM) modules. It supports up to four PWM channels, each with configurable pin mapping. Timer 2 is utilized by this driver to manage PWM periods. +The driver provides PWM output functionality for the PIC18F26K83 using the CCP (Capture/Compare/PWM) modules. It supports up to five PWM channels (CCP1-CCP5), each with configurable pin mapping through the pin configuration module. Timer 2 is utilized by this driver to manage PWM periods. -Integration -=========== +Features +======== -Pin Configuration ------------------ -.. c:macro:: CONCAT(a, b, c) - - Concatenates three tokens to dynamically form register names. - - :param a: First part of the token. - :param b: Second part of the token. - :param c: Third part of the token. - -.. c:macro:: CCPR_L(module) - - Accesses the CCPR Low register for the specified module. - - :param module: CCP module number (1-4). - -.. c:macro:: CCPR_H(module) - - Accesses the CCPR High register for the specified module. - - :param module: CCP module number (1-4). - -.. c:macro:: CCP_CON(module) - - Accesses the CCPxCON control register for the specified module. - - :param module: CCP module number (1-4). - -.. c:macro:: GET_TRIS_REG(port) - - Retrieves the TRIS register for the specified port. - - :param port: Port letter (A, B, C). - -.. c:macro:: GET_PPS_REG(port, pin) - - Retrieves the PPS register address for the specified port and pin. +* Support for CCP modules 1-5 for PWM output generation +* Configurable PWM period and duty cycle +* Timer 2 integration for period management +* Separation of concerns: pin configuration handled by dedicated pin configuration module +* BARR-C compliant implementation with proper error handling - :param port: Port letter (A, B, C). - :param pin: Pin number (0-7). - -.. c:macro:: SET_TRIS_OUTPUT(port, pin) - - Sets the specified pin as output by modifying the TRIS register. - - :param port: Port letter (A, B, C). - :param pin: Pin number (0-7). - -.. c:macro:: ASSIGN_PPS(port, pin, ccp_module) - - Assigns the CCP module to the specified PPS register to map the peripheral to the desired pin. - - :param port: Port letter (A, B, C). - :param pin: Pin number (0-7). - :param ccp_module: CCP module number (1-4). - -CCP Mode Configuration ----------------------- -.. c:macro:: CONFIGURE_CCP_MODE(ccp_module, ccp_con) - - Configure the CCP module for PWM mode. - - :param ccp_module: CCP module number (1-4) - :param ccp_con: CCPxCON register to configure - -Output Pin Configuration ------------------------- -.. c:macro:: SET_PWM_OUTPUT_PIN(ccp_module, output_pin) - - Set the TRIS register for the output pin. - - :param ccp_module: CCP module number (1-4) - :param output_pin: Output pin number - -Duty Cycle Configuration ------------------------- -.. c:macro:: WRITE_DUTY_CYCLE(ccp_module, duty_cycle) - - Write the 10-bit duty cycle value to the appropriate CCPRxH:CCPRxL register pair. +Prerequisites +============= - :param ccp_module: CCP module number (1-4) - :param duty_cycle: 10-bit duty cycle value (0-1023) +Before using the PWM driver, you must configure the output pins using the pin configuration module: + +.. code-block:: c + + // Configure PWM output pin first + pwm_pin_config_t pwm_config = { + .output = {.port = 1, .pin = 5} // RB5 for PWM output + }; + w_status_t status = pps_configure_pwm(1, pwm_config); + if (status != W_SUCCESS) { + // Handle configuration error + } + + // Then initialize PWM module + status = pwm_init(1, 1000); // CCP1, period = 1000 + if (status != W_SUCCESS) { + // Handle initialization error + } PWM Controller Functions ======================== -PWM Pin Configuration Structure -------------------------------- -.. c:type:: pwm_pin_config_t +PWM Pin Configuration +----------------------- - Structure that holds the configuration details for a PWM pin. +The PWM pin configuration uses the :c:type:`pwm_pin_config_t` structure defined in the pin configuration module. This structure contains a single output pin configuration that specifies where the PWM signal should be routed. - :param port: Port letter (A, B, C). - :param pin: Pin number (0-7). - :param pps_reg: PPS register value for this pin. +For details on the structure definition, see the :doc:`pin_config` documentation. Initialization -------------- -.. c:function:: w_status_t pwm_init(uint8_t ccp_module, pwm_pin_config_t pin_config, uint16_t pwm_period) +.. c:function:: w_status_t pwm_init(uint8_t ccp_module, uint16_t pwm_period) - Initializes PWM for the specified CCP module with the given pin configuration and PWM period. + Initializes PWM for the specified CCP module with the given PWM period. - :param ccp_module: CCP module number (1-4). - :param pin_config: PWM pin configuration structure containing port, pin, and PPS register values. + :param ccp_module: CCP module number (1-5). :param pwm_period: PWM period value. :return: W_SUCCESS on successful initialization, otherwise an error code. This function configures Timer 2, sets the PWM period, and enables the PWM output for the specified CCP module. + + .. note:: + Pin configuration must be done separately using :c:func:`pps_configure_pwm` from the pin configuration module before calling this function. PWM Operation ============= @@ -122,7 +66,7 @@ PWM Operation Updates the duty cycle of the specified CCP module to the new value. - :param ccp_module: CCP module number (1-4). + :param ccp_module: CCP module number (1-5). :param duty_cycle: New duty cycle value (0-1023). :return: W_SUCCESS if successful, W_INVALID_PARAM if parameters are out of range. @@ -130,24 +74,18 @@ PWM Operation Timer Configuration ------------------- -.. c:macro:: CONFIGURE_TIMER2(pwm_period) - - Configures Timer 2 to manage PWM periods. The prescaler and postscaler are set to 1:1. - :param pwm_period: PWM period value to load into the PR2 register. +The PWM driver automatically configures Timer 2 to manage PWM periods. The prescaler and postscaler are set to 1:1 for optimal resolution. The PWM period is set during initialization via the ``pwm_init()`` function. Helper Functions ================ PPS Configuration ----------------- -.. c:function:: static w_status_t configure_pps(uint8_t ccp_module, pwm_pin_config_t pin_config) - Configures Peripheral Pin Select (PPS) for the specified pin and CCP module. This function is essential for routing the PWM signal to the correct output pin. +PPS (Peripheral Pin Select) configuration for PWM is handled by the pin configuration module. Use :c:func:`pps_configure_pwm` to configure the output pin before initializing the PWM module. - :param ccp_module: CCP module number (1-4). - :param pin_config: Structure containing port, pin, and PPS register values. - :return: W_SUCCESS if successful, W_INVALID_PARAM if the module number is out of range. +See the :doc:`pin_config` documentation for details on PWM pin configuration. Error Handling ============== diff --git a/doc/spi_driver.rst b/doc/spi_driver.rst index 62f31a0..a893073 100644 --- a/doc/spi_driver.rst +++ b/doc/spi_driver.rst @@ -1,10 +1,56 @@ -SPI Driver (Not Implemented) -***************************** +SPI Driver +********** -Features -======== -- SPI register read/write function -- Chip select signal toggle by GPIO driver +The SPI driver provides master mode communication functionality for the PIC18F26K83. The driver focuses on SPI protocol implementation, while pin configuration is handled separately by the dedicated pin configuration module. + +**Key Features:** + +* Master mode operation (slave mode not currently supported) +* Support for SPI1 and SPI2 modules +* 8-bit register read/write functions for peripheral devices +* Chip select signal management through GPIO integration +* Separation of concerns: pin configuration handled separately + +**Current Status:** Interface defined, implementation pending + +Prerequisites +============= + +Before using the SPI driver, you must configure the SPI pins using the pin configuration module: + +.. code-block:: c + + // Configure SPI1 pins first + spi_pin_config_t spi_config = { + .sck = {.port = 2, .pin = 0}, // RC0 for Serial Clock + .sdi = {.port = 2, .pin = 1}, // RC1 for Serial Data Input + .sdo = {.port = 2, .pin = 2}, // RC2 for Serial Data Output + .ss = {.port = 2, .pin = 5} // RC5 for Slave Select (optional) + }; + + // Configure with slave select enabled + w_status_t status = pps_configure_spi(1, spi_config, true); + if (status != W_SUCCESS) { + // Handle configuration error + return -1; + } + + // Then initialize SPI module + spi_init(freq_divider); + +For details on SPI pin configuration, see the :doc:`pin_config` documentation. + +Design Features +=============== + +**Master Mode Operation:** +The driver is designed for master mode operation where the MCU controls the clock and initiates all communications. + +**Chip Select Management:** +Chip select (CS) signals are managed through GPIO driver integration, allowing flexible control of multiple SPI devices. + +**Register-based Communication:** +Optimized functions for common peripheral register operations (read/write 8-bit registers). SPI Controller Functions ======================== @@ -13,44 +59,313 @@ Initialization -------------- .. c:function:: void spi_init(uint8_t freq) - Initialize SPI module and set up pins. + Initialize SPI module for master mode operation. + + :param freq: Frequency divider for SPI clock generation + :type freq: uint8_t + + .. note:: + Pin configuration must be completed using :c:func:`pps_configure_spi` before calling this function. + + .. note:: + Exact frequency calculation is TBD and will be documented when implementation is complete. - :param uint8_t freq: frequency divider, exact meaning TBD +Low-Level Transfer Functions +----------------------------- -Transmit --------- .. c:function:: void spi_tx(uint8_t data) - Transmit SPI + Transmit a single byte via SPI. - :param uint8_t data: 8 bit data to write + :param data: 8-bit data to transmit + :type data: uint8_t + + This function initiates an SPI transmission. For full-duplex operation, combine with :c:func:`spi_rx`. -Receive -------- .. c:function:: uint8_t spi_rx(void) - Receive SPI + Receive a single byte from SPI. - :return: Received byte + :returns: Received data byte :rtype: uint8_t + + This function reads the SPI receive buffer. In master mode, a transmission must be initiated first to generate the clock for reception. + +High-Level Register Functions +----------------------------- + +These functions are designed for easy peripheral device register access: -Write 8-bit Register --------------------- .. c:function:: void spi_write8(uint8_t reg_addr, uint8_t value) - Write to a 8-bit register of a SPI peripheral. - Note that toggle CS line have to be done before and after calling this function. + Write to an 8-bit register of an SPI peripheral device. - :param uint8_t reg_addr: 8 bit register address - :param uint8_t value: 8 bit data to be written + :param reg_addr: 8-bit register address + :type reg_addr: uint8_t + :param value: 8-bit data to be written + :type value: uint8_t + + .. important:: + Chip select (CS) line must be toggled manually before and after calling this function. -Read 8-bit Register -------------------- .. c:function:: uint8_t spi_read8(uint8_t reg_addr) - Read from a 8-bit register of a SPI peripheral. - Note that toggle CS line have to be done before and after calling this function. + Read from an 8-bit register of an SPI peripheral device. - :param uint8_t reg_addr: 8 bit register address - :return: data read from the register + :param reg_addr: 8-bit register address to read from + :type reg_addr: uint8_t + :returns: Data read from the register :rtype: uint8_t + + .. important:: + Chip select (CS) line must be toggled manually before and after calling this function. + +Usage Examples +============== + +Basic SPI Setup and Communication +--------------------------------- + +.. code-block:: c + + #include "pin_config.h" + #include "spi.h" + #include "gpio.h" + + int main(void) { + // Initialize MCU + mcu_init(); + + // Configure SPI1 pins + spi_pin_config_t spi_config = { + .sck = {.port = 2, .pin = 0}, // RC0 + .sdi = {.port = 2, .pin = 1}, // RC1 + .sdo = {.port = 2, .pin = 2}, // RC2 + .ss = {.port = 2, .pin = 5} // RC5 + }; + + w_status_t status = pps_configure_spi(1, spi_config, true); + if (status != W_SUCCESS) { + // Handle pin configuration error + return -1; + } + + // Configure CS pin as GPIO output (for manual control) + gpio_enable_output(C, 5); // RC5 as CS + gpio_set_output(C, 5, 1); // CS idle high + + // Initialize SPI module + spi_init(4); // Example frequency divider + + while(1) { + // Example: Read device ID from SPI device + gpio_set_output(C, 5, 0); // Assert CS + uint8_t device_id = spi_read8(0x00); // Read ID register + gpio_set_output(C, 5, 1); // Deassert CS + + // Process device_id... + + delay_ms(1000); + } + } + +Multiple SPI Device Management +------------------------------- + +.. code-block:: c + + #include "pin_config.h" + #include "spi.h" + #include "gpio.h" + + // Define chip select pins for different devices + #define FLASH_CS_PORT C + #define FLASH_CS_PIN 5 + #define SENSOR_CS_PORT C + #define SENSOR_CS_PIN 6 + + // Helper functions for chip select management + void flash_cs_assert(void) { + gpio_set_output(FLASH_CS_PORT, FLASH_CS_PIN, 0); + } + + void flash_cs_deassert(void) { + gpio_set_output(FLASH_CS_PORT, FLASH_CS_PIN, 1); + } + + void sensor_cs_assert(void) { + gpio_set_output(SENSOR_CS_PORT, SENSOR_CS_PIN, 0); + } + + void sensor_cs_deassert(void) { + gpio_set_output(SENSOR_CS_PORT, SENSOR_CS_PIN, 1); + } + + int main(void) { + mcu_init(); + + // Configure SPI pins (shared by both devices) + spi_pin_config_t spi_config = { + .sck = {.port = 2, .pin = 0}, // RC0 + .sdi = {.port = 2, .pin = 1}, // RC1 + .sdo = {.port = 2, .pin = 2}, // RC2 + // Note: .ss not used for manual CS control + }; + pps_configure_spi(1, spi_config, false); // No automatic SS + + // Configure individual CS pins + gpio_enable_output(FLASH_CS_PORT, FLASH_CS_PIN); + gpio_enable_output(SENSOR_CS_PORT, SENSOR_CS_PIN); + flash_cs_deassert(); // CS idle high + sensor_cs_deassert(); // CS idle high + + spi_init(4); + + while(1) { + // Communicate with flash memory + flash_cs_assert(); + spi_write8(0x06, 0x00); // Write enable command + flash_cs_deassert(); + + delay_ms(10); + + // Communicate with sensor + sensor_cs_assert(); + uint8_t temp_data = spi_read8(0x00); // Read temperature + sensor_cs_deassert(); + + // Process data... + delay_ms(1000); + } + } + +Advanced Register Operations +----------------------------- + +.. code-block:: c + + // Example: Configure an accelerometer via SPI + void accelerometer_init(void) { + // Assert CS + gpio_set_output(ACCEL_CS_PORT, ACCEL_CS_PIN, 0); + + // Configure control register 1: 50Hz, XYZ enable + spi_write8(0x20, 0x47); + + // Configure control register 4: +/-2g scale + spi_write8(0x23, 0x00); + + // Deassert CS + gpio_set_output(ACCEL_CS_PORT, ACCEL_CS_PIN, 1); + } + + void read_acceleration(int16_t *x, int16_t *y, int16_t *z) { + uint8_t accel_data[6]; + + gpio_set_output(ACCEL_CS_PORT, ACCEL_CS_PIN, 0); + + // Read 6 bytes starting from X_L register + for (uint8_t i = 0; i < 6; i++) { + accel_data[i] = spi_read8(0x28 + i); + } + + gpio_set_output(ACCEL_CS_PORT, ACCEL_CS_PIN, 1); + + // Combine low and high bytes + *x = (int16_t)((accel_data[1] << 8) | accel_data[0]); + *y = (int16_t)((accel_data[3] << 8) | accel_data[2]); + *z = (int16_t)((accel_data[5] << 8) | accel_data[4]); + } + +Architecture Integration +========================= + +SPI Bus Sharing +--------------- + +The SPI driver is designed to support multiple devices on the same SPI bus: + +.. code-block:: text + + MCU (Master) + | + +----- SCK ----+---- Device 1 (SCK) + | | + +----- SDI ----+---- Device 1 (SDO) + | | + +----- SDO ----+---- Device 1 (SDI) + | | + +----- CS1 ---------- Device 1 (CS) + | | + +----- CS2 ----+----- Device 2 (CS) + | + +----- Device 2 (SCK) + | + +----- Device 2 (SDI) + | + +----- Device 2 (SDO) + +**Key Points:** +* SCK, SDI, SDO are shared among all devices +* Each device has its own CS signal +* Only one device should be active (CS asserted) at a time + +Layer Responsibilities +----------------------- + +.. code-block:: text + + Application Layer + | + +-----v-----+ + | SPI | <- High-level register operations + | Driver | Low-level transfer functions + +-----------+ + | + +-----v-----+ + | GPIO | <- Chip select management + | Driver | + +-----------+ + | + +-----v-----+ + | Pin | <- SPI pin configuration and PPS routing + | Config | + +-----------+ + | + +-----v-----+ + | Hardware | <- SPI peripheral registers + | SPI | + +-----------+ + +**Integration Benefits:** +* **Modular Design**: Each layer has specific responsibilities +* **Reusability**: GPIO and pin config layers used by other peripherals +* **Testability**: Each layer can be tested independently +* **Flexibility**: Easy to add new SPI devices or change pin assignments + +Implementation Status +====================== + +**Current Status:** Interface defined, implementation pending + +**Planned Features:** +* Full-duplex and half-duplex communication modes +* Configurable clock polarity and phase (CPOL/CPHA) +* Multiple frequency options +* Interrupt-driven operation for improved performance + +**Design Considerations:** +* **Clock Configuration**: SPI clock will be derived from system clock with configurable dividers +* **Buffer Management**: Transmit and receive operations will be optimized for common use cases +* **Error Handling**: Status reporting for communication errors and timeouts + +**Integration with Other Modules:** +* **GPIO Driver**: Used for chip select signal management +* **Pin Configuration**: Handles SPI pin routing and electrical configuration +* **Timer Module**: May be used for timeout functionality + +**Future Enhancements:** +* DMA support for high-speed transfers +* Multi-master mode support +* Hardware-controlled chip select for single-device scenarios +* Automatic protocol handling for common device types (EEPROM, ADC, etc.)