From 30ecd7ad83a78fd50baff791b934af260f9c5e39 Mon Sep 17 00:00:00 2001 From: wrh Date: Wed, 22 Jul 2026 11:28:46 +0800 Subject: [PATCH] =?UTF-8?q?refactor(chrg):=20=E7=A7=BB=E9=99=A4=E4=BD=8E?= =?UTF-8?q?=E7=94=B5=E5=8E=8B=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E5=B9=B6=E4=BC=98=E5=8C=96=E7=94=B5=E5=8E=8B=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 删除chrg_source.h中冗余的voltage、current成员变量 2. 删除chrg_source.c中的chrg_source_work_low低电压处理函数及其调用逻辑 3. 在chrg_north.c新增电压误差阈值和重试帧数宏定义 4. 重构北向电源解析逻辑,增加连续超差重试机制和参数校验 5. 优化电压误差计算方式,避免无符号减法下溢问题 --- apps/chrg/applications/thread/chrg_north.c | 70 ++++++++++++++---- apps/chrg/applications/utils/chrg_source.c | 19 ----- apps/chrg/applications/utils/chrg_source.h | 3 - ...可编程双向电源通信协议V_2.0 - 副本(1).xlsx | Bin 0 -> 17467 bytes 4 files changed, 54 insertions(+), 38 deletions(-) create mode 100644 docs/副本BMP4810300-4多协议可编程双向电源通信协议V_2.0 - 副本(1).xlsx diff --git a/apps/chrg/applications/thread/chrg_north.c b/apps/chrg/applications/thread/chrg_north.c index 75c83a0..ea4f291 100644 --- a/apps/chrg/applications/thread/chrg_north.c +++ b/apps/chrg/applications/thread/chrg_north.c @@ -24,6 +24,9 @@ #define DBG_LEVEL DBG_LOG #include +#define SOURCE_VOLT_ERROR_MV 200U +#define SOURCE_VOLT_RETRY_FRAMES 3U + /***************************************************************** 函数名称: chrg_source_standard_output 功能描述: 南向功率源标准输出控制函数 @@ -52,37 +55,72 @@ void chrg_source_standard_output(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) 函数描述: 解析北向电源板电压电流回码并驱动Source状态机 输入参数: frame_data:完整北向回码 idx:当前通道 pSW:通道控制结构体 pNOR:北向总控结构体 -输出参数: 更新协商电压、电流、source.work_mode及上次下发电压缓存 +输出参数: 更新电压、电流、source.work_mode及电压重试计数 返回说明: - 其它说明: frame_data[4~7]为实测值,[8~11]为协议协商目标值; - 目标电压变化时进入RUNING,相同时进入WAIT + 新目标立即进入RUNING;实际误差连续3帧超过200mV时重发 *****************************************************************/ void chrg_source_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx, struct chrg_switch_t *pSW, struct chrg_north_t *pNOR) { - rt_uint16_t volt_mv = (frame_data[8] << 8) | frame_data[9]; - rt_uint16_t Curr_mA = (frame_data[10] << 8) | frame_data[11]; - rt_uint16_t volt_mv_Now = (frame_data[4] << 8) | frame_data[5]; - rt_uint16_t Curr_mA_Now = (frame_data[6] << 8) | frame_data[7]; + rt_uint16_t volt_mv; + rt_uint16_t curr_ma; + rt_uint16_t volt_error; static rt_uint16_t last_volt_mv[TOTAL_SOU_CHS] = {0}; - static rt_uint8_t number = 0; + static rt_uint8_t last_volt_valid[TOTAL_SOU_CHS] = {0}; + static rt_uint8_t volt_retry_count[TOTAL_SOU_CHS] = {0}; + rt_bool_t need_set = RT_FALSE; int ret; - if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { + if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL) || + (frame_data == RT_NULL)) { return; } + volt_mv = (frame_data[8] << 8) | frame_data[9]; + curr_ma = (frame_data[10] << 8) | frame_data[11]; + /* 保存北向协议板返回的实测值和协商目标值。 */ pSW->source.vc.set_voltage = volt_mv; - pSW->source.vc.set_current = Curr_mA; - if (pSW->source.On_Flag) { - if ((volt_mv == last_volt_mv[idx])) { - pSW->source.work_mode = SOURCE_WORK_WAIT; - } else { - pSW->source.work_mode = SOURCE_WORK_RUNING; + pSW->source.vc.set_current = curr_ma; + + if (!pSW->source.On_Flag) { + /* 关机后清除历史值,确保下次启动至少下发一次目标电压。 */ + last_volt_valid[idx] = 0; + volt_retry_count[idx] = 0; + return; + } + + /* 使用绝对误差,避免无符号减法在实际电压较小时发生下溢。 */ + volt_error = (pSW->Now_voltage >= volt_mv) ? + (pSW->Now_voltage - volt_mv) : + (volt_mv - pSW->Now_voltage); + + if (!last_volt_valid[idx] || (volt_mv != last_volt_mv[idx])) { + /* 首次设置或目标变化,立即进入RUNING下发新电压。 */ + need_set = RT_TRUE; + } else if (volt_error <= SOURCE_VOLT_ERROR_MV) { + /* 实际电压已进入允许范围,清除连续失败计数。 */ + volt_retry_count[idx] = 0; + } else { + /* 给功率板三个反馈周期的稳定时间,避免每帧重复写电压。 */ + if (volt_retry_count[idx] < SOURCE_VOLT_RETRY_FRAMES) { + volt_retry_count[idx]++; } - } + + if (volt_retry_count[idx] >= SOURCE_VOLT_RETRY_FRAMES) { + need_set = RT_TRUE; + } + } + + /* 解析函数只决定状态,具体寄存器操作仍由Source状态机执行。 */ + pSW->source.work_mode = need_set ? + SOURCE_WORK_RUNING : SOURCE_WORK_WAIT; + ret = chrg_source_work_state(idx, pSW); - if ((ret >= 0) && (pSW->source.work_mode == SOURCE_WORK_RUNING)) { + if ((ret == 0) && need_set) { + /* 成功入队后更新缓存;重发成功后重新开始计算连续超差帧数。 */ last_volt_mv[idx] = volt_mv; + last_volt_valid[idx] = 1; + volt_retry_count[idx] = 0; } } diff --git a/apps/chrg/applications/utils/chrg_source.c b/apps/chrg/applications/utils/chrg_source.c index c437f8c..f8c8c23 100644 --- a/apps/chrg/applications/utils/chrg_source.c +++ b/apps/chrg/applications/utils/chrg_source.c @@ -111,23 +111,6 @@ static int chrg_source_work_running(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) return chrg_sou_com_batch_submit(idx, ®, &value, 1); } -/***************************************************************** -函数名称: chrg_source_work_low -函数描述: 执行电源低电压异常状态,停止功率板输出 -输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 -输出参数: - -返回说明: 0:停止命令提交成功 非0:命令提交失败 -其它说明: 本函数只发送WORK_STOP,不关闭通道使能和北向继电器 -*****************************************************************/ -static int chrg_source_work_low(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) -{ - /* 电压异常时先停止功率板输出,保留状态供上层判断。 */ - rt_uint16_t reg = REG_WORK; - rt_uint16_t value = WORK_STOP; - - return chrg_sou_com_batch_submit(idx, ®, &value, 1); -} - /***************************************************************** 函数名称: chrg_source_work_stop 函数描述: 执行电源主动关机流程 @@ -211,8 +194,6 @@ int chrg_source_work_state(rt_uint8_t idx, struct chrg_switch_t *pSW) return chrg_source_work_wait(idx, pSW); case SOURCE_WORK_RUNING: return chrg_source_work_running(idx, pSW); - case SOURCE_WORK_LOW: - return chrg_source_work_low(idx, pSW); case SOURCE_WORK_STOP: return chrg_source_work_stop(idx, pSW); case SOURCE_WORK_SWITCH: diff --git a/apps/chrg/applications/utils/chrg_source.h b/apps/chrg/applications/utils/chrg_source.h index a17fb38..937b0a7 100644 --- a/apps/chrg/applications/utils/chrg_source.h +++ b/apps/chrg/applications/utils/chrg_source.h @@ -145,9 +145,6 @@ struct src_vc_t { #define PD_GEAR_ARRAY_LEN 4 // 非5V挡位最多4个,数组长度设为4 // source 参数结构 struct chrg_src_t { - rt_uint16_t voltage; // 当前电压 mV - rt_uint16_t current; // 当前电流 mA - eSRC_PRO protocol; // 协议类型 rt_uint8_t src; // 源类型 rt_uint8_t pps; // PPS类型 diff --git a/docs/副本BMP4810300-4多协议可编程双向电源通信协议V_2.0 - 副本(1).xlsx b/docs/副本BMP4810300-4多协议可编程双向电源通信协议V_2.0 - 副本(1).xlsx new file mode 100644 index 0000000000000000000000000000000000000000..83074575fe13d3c35980de020a65e0c0b70c1f5e GIT binary patch literal 17467 zcmeIag;!i%vObKvy9T%5?(XjH?(XjH9)fFdcW4Oi8rlKbjzAT33wdtcc%<$uL+OVVDnluH=q|DkAuW$pD`Z%0V8N zPI*UqH9@4QT(OKeJc5;IailiXJ3AGbnAJ#YGM({N=~C`vsnF^a+8Un-Bu_?X(eiZb zEU>wR2?Q)FflFJbVmJ#j)D6cdMIS^3*O8&piJZ+vLAYy)sEwzK;Pe>_XxteE5ETJpoBb+FekhgGj|MKynSSDYlRlcfFee z4@m_l7*yOJ;P*1Ry3P}OGE8*0!%`WIg2qkK>|Pa?{^aNi`I+1)P0X=!yC2zY{&xN@ zLtM&}(hU&*xuUf+UwUMdMC`{ekvgO)I&~aq)MC6a4Bm`DtwCAM4Wox@;CUhCpH*SC zE$n$G$y1sBi)kgt@ca>+GH0_H=)=xN=F8PS!!|^>k2tEz7Mzx~MmbJg#Gd*lHs7yB zGP_YUWd-k(K_f-sEjs!&$lx}=Ptp79;`tR?4 zxu8Hmiyxs4@k25mHuUcHPS!^D_SV1SSf%Q^)vg#?7yS)>$T|AN(NLXe%0M$I8xsAX zV=@Mu8F6eOQPLoOtZ}%h;RQ^nX^k7bSIZ6G4g3?+`gE7*ltdbSjkIF}`d!R{_@>Wc z)&#!pO&RKPqB<~6mwF=KV)IlGVKympoHxV(i{dQ70FPgdYWlLHH~N03e_O< zI6^_>PH4!0exi5M8paWsj*-aIFR{^Mv+(qR(vj=`X=K;WlMC9d2vZCaFK z*h?zw^NJPbBiVv#kg7564V%_e9&2NBdT=Z@DGUr6;me+^f+jM{M^7qYEBk6~s%m(z zj6l2~b~6Nyisl4K3U(kMZ4|GQE=;U!OT?s)*f}!R#fS$N8(lGiG>)V^Abx2h5fx;X z+*6zJC2g!Mcx_}ieDl*LuaDpR_3lvaC;nG1Ph#czT-0~LQc^WPrXF_I_or8B{y^+r z>wb!E-_$!XT4ufccicjeN9*hsP7wk>;>1c)p=1{*XhKpM}d)oHd?1 z$sBZ68h*hRJQj(T-uQ@6$>}h)g}yuCxVJQDy_Fin6$Z`ntVirZeEt*tSF@k7Od9j8 z(qifRY9v;rRn;1am&G->Sc0*goA`7U1Jr55bBnaAPJ*ttYto~3N(M2s;<7??lxAIB zeUzoxqL*0Z%Z4U=`6{Z)d1|*>il*Q7?foBj@8xqh0q@t_z)>ybEu-@awISc+P|TsL zg_eErl4(A{$hxY^aA9fUHw9Pkc~Vt;x)}~2byK*<5)4qV=m`69t|7KsM_YISrgrox zTyV)*HDxY)>y;q2P71cB%?52O1&R}cv@4X_O2nL3DX7vaIN(CLp0{OPm`%Zj7!Moa zoUm}wnllVnq}e+r*zZV8yMFX#nfX*{wX&;3gpM#@l}_DQzG=qGjhVB8Vqs=wM8F=6 zvb(1HttA%Iz*h`$4Nvz|Yu&pQ!zaAfdmcRbngU^VcSt~<_ru${#oVhQp5G>(;aj2b z#OJN@DibR4uKH>_Sg`rh1A9HPT46N>0S=ce9E6xm{OdL7E=aKFsrCV#w{D z6=4Sy^|pt)GztaG3)SX=8{B^4dIA*6=x5cZAaQV1l(Uo5il49uU!76g_>zWca?m&q z9w^DM!wXA@MQ++=!&s~)8C;pHoTu?eKm7k#<6gj1i1JxgP-9CA;a4iN{r5KE)jNpX zAWwpsYiwvq9(YfnnWH%(>W3cDJE*J97c*JUN$Z}%C%ApQ3h7Vfth_#9E`;I3;spLw zNzVHP86Bz@+b%-Sqg36iS2SZc7iN1SL-U&-EB&ADUpMn7sRB9>khd!k5Z1?tf4YBX z3sX}UXZpV`jKAYRqwcEHszj3SX2dHb#3n5?re5DwhzLqRdnR!SAl>|HiLID)L0Zwz z^Nl6{O&UVj;c?{>vRDpA<^sfel+ffzk?hYp8*jT)&mEI3w|3pjd^&E04bgVyueB?F zYdk((XK#o8CiY?LlW(;?53QZ6e3kSa{#Ezu{+-YF{@%~N9nZ$^rT{*d;l94N`saNI z54_ym3w8a4`?1&MJI7Z6Z9ZG~`!Ud0=le&W_f~Csezn;1i^<*S=(opLr|an|-WYfJ zUv;lHmJM3+EfqEQr{TgsOvJ6GS$oI+e(zv{!szt2@{*KvJYoAEb((%*4c-md-jJYm(cZqJWDIehK8ZqD;E z^LXUbX2rApi+@BmCFf#clZ`H*s^Y;^H_9uvrqwmAb6T_8@!)7Bw%d+R&+XlvL-yH` zDPmK`JorY|ixmsd7PqsJIYTK~NIGhke0ucWezD=VrVz5O=<0SVpT1sU@#4pEl+*34 zO*ZXsyRdn`<9=BCa_Q&WqKCiGm|VKbX+z+z?aw8%;O;)>G5zxeu)fi)PpiuSnX*5@ zZ?7Ac6bq`WdjsEZ(~o{3b4nj!Zg($cvhj1~Ai?|B>U(M_`;+gQYtDY^tK3dP z@0)F#t=B2D&X4A|_s<8r+heBel9M|Y97nF)1Pjl?&5m>(+4GC9hTiX+O_Kd_R+w|I zqu{Tmm@}6&k~`5MLBCAs(UwMGUvKrq%!7LfC6mo>$V};P7QG{LJvrv~%Sm1bMVWX` zZ)e|}Ir3@BvZnRrsmTVAQK(E*L7&Fp!)~r6f|1$ty4MI}bJiy!xKzV8i)kR;9nwk^ zy=MHyE(^$GkHYVTJvq)0b5f-er^xOL;SF3Ez2s0t_|n%9<^5lR3a^&YnvPRMrsPM5 zzok5HKPTthK2MQmFx4ZZNlYA?x$mJ)yl!>fhhM)vgm$FyVy8y-sE;^%dfp4 zNI&1fk0p_kRFBwsfDEN9)@pUCs@7>3vpb18Gj*50Y;jk7xqHD)?L=SIVP~uMXj4NK zC)geXN^} zylbo*mnrl@!#)!VL}o^Cn(`wg3i-;!Ga(E>*$y+E`3|!&jWXPbC(Vt6b&9PNbvJ$Q1t|tXGiNDL&zi~a$amsZs|nR)CFJ6Q zD8R_!J&f0x&P@Z%)nhW9=pL!$fW^ufW<$h|=UHR0Fr~lJSeQiV>fsi%tk}d?n@{!> zFkT&QW%;%&JHZZvBq$MoHnTe)LGUZ+If^-%`8DSTPsLIH9Etxn$7biSiDzUZth`E^ zqD(x@<)hr37-_IJ4zeB@BRk0EB=05ena4~H48uq6i5*=Kc*ksBSfaA7WndVn1oT;e zC5un=)!nY*^0B|Y8X2F)IZDO~7beY~)wGC~lKC==k(mDFfM&ACQISMR=8MF5TOaKR zhK5ESS^)9#$g6U#&f`1_bCD-oIGZ7fWMeqkk0ajegsl~fzO_{eJ8|;h=!McUo~}dM z?Eo4eDzXAjcP}{UscxQ07iBu~ChXa)Oe0o9k^xR>tr1R-sTTyY!-M`2KMKP{Gz2S zX3tX{9a|S&x}`x`e^&L(z~lWjT#dVf4%-Tx}cTJ>v>LIPL{iqrJA?17DG(FCg-TvqHKw?NB>S-Y*QRu;PR6iqIf3br)aupAqN-DeQd2w zNV2w>)4oI)P?ot(F?q-~kHPU$iAT@G9P54W-eguR={})yPf1Ed$y#JZ$woKvJ`KS> zNBDk05gsYpDpb|U!Y0lB7LPHtBxj6M>-;aPO{}KEN1UV>ZIhl3dt0eU%0c5|E&cdk zqcv((aAjP^SC%`rV7s4CB;zKT5l5a34(zTL+Op`FQz5(=%q0{M{vj+UGA;c?C$uWY zX!(pix2y40iBZLd`qWl0^G``B+7nTeuptLsAZI-=I1V|@^Yt(3A_W@t}BC7u}dA%5u5X9kZwKKyT;j8>-|=vghD?3z{r zDN?wykC7r}nemM&g_QWctmvXt-bn>$*}rAqx0U!@M4A*Sy^TLY(}Hr7_MspPB`Itl zW>q7ns3E|vH&jVyN*n%*Yjv2$Tml2bA*arnO6r-x%?8ZedjLD56>TH22v3CyS8}vU zmdX}we@e9oCuR(dt>=^wsLO0f>+wFE?#JAZ=fE)d zYp`d_=O!DyNk%?~-+T;rvQua8jFobBrbDYz9BWI>Yq25aY+);IoXN_SNFlEz-Cz4Y zypeel3ntG97KlGWm?vc_?^JqDgbl_$acUcfV5C*Z2Bns?QJ)AG)I?Pri_jY>V%0mU zG!EzS@ho8D{l9g#us*ebr%3T965laG*|Lz+znqTOk0i%?34ws2wjpMt+|(s# z8Z94N2wR9#C^Wp^83JyksOhWIZ!eA(XsKW-hRNUU2(Yre&+;APp=CJ=DgUXVq zDk)XNPC~9_8p#|6%2N~F{2*|4aOYkf1`7w;60&hI%%wBnX9B6s`^!&&$rb6YUk}~k z8H|)w2RoqTshFxeU10(~Y=g13zRZ@~jQA%i#F6)8!rmIp5Ac7kT6w#<2JK;M&ex?! zH#_o+zUzca?k%3{=j4>tkQF^5TS!`^M1Gu7jPPXuU!)Mga1Wcgsw;JIGezRKI^%~`kh4mW!JZEiBc7rCQ9AXA#3bhY~{t3k^ zibygqH5c~x6G8iw6Z#$`gIYGEEn|$#by)_)nkao!7_}DXSJbv~QLzR0nqya`xnAch zXHzDbfRXg1Nty>^r4MNHGS%CuiI22bXITHOSS?uPl*`MY0rav zV=Za}V`=2f*31QMfVUyo!>D9!~cyA$9dkn+EOfXw~ z*XQxj)y?WbM$cd(fxfxSq@VwxIu;A^MULL3j=V*hEiEi{sYdvwbnR0-E;2?<6QrjJ zZ`1dj>?xJO)qh#WE$Z>grxPtiss-gz4oaK0e6;2xzUyhmRP zbt`?YQ*)C+b+MmkDAfSp)WS@G4-)}~pqc0}vnpU@d(ou=GfS|QV!hEGOA?NOeL-)B|g?}L09LZXP2`%33Gt&?L;&SO@w5d<%SrRU^2&3wWM zQH3%K+IH@obHejT))lFhZ|=rgEA|WOP`# z1&S8wGkQ_!Ipn~cbZIq@<>MZat8J4!acyGJim=gM+(tvdePA~8pc%LjJDg-W?;I2S zKY+kNo}L%-L}|iP>q^>6h#Bqx(?;zHZ)6Ap$2WEFOw;A&Y&_BB3R16bLkUKGcWH7? zZD@-?g)+j4w@4Rd0@vj5JqAdo9I~V@j9X?-FL9F%0oPEUxcc0Ff6sisb-f&^`xB)* z59vrfO0uoWPW@ZrK5&-#hv0l2MdGqQe@uf?WFgW-l3;O@rzol{8`GR*0HbDAve^Nc z?r6OW8q`~rQsOXi4wFU5qu4#{#xdi=Ofz!OCv1wo^tdwJ&(B&Hl`^#S80kv5FkiVp)S48Z`F{!St3l35wqnn*vkT)woI* z9#DNJ>Yh_F;p)9Z#G7n7YmC##B-W6SsG2HYJF+|ofX&tOvNxOaEcEsj;3i3I+@4<> zHF|ZjYs(}5>AesJH@^vArU$slcLOnsnug1V%g@T^7ze_1o)F;9&%;hY|AHMse~BK= zKSEa>@zdbh%Ys6kJf<<_pTDh`g%C%c4SlxrKil8_%3yj*-i4AGn7-#3x2_52z(g%} zOWBE?YY)7jZs)}&XKiTbIs`!XR_VmiHSVi$zNgR%3fFL_cs98%7ROgT5nCa^r1uRKrB*zY zLUP=oI*VkSHhH5d${JHK?T@WA{Q^c`Gcey*l=$Oa3}7DYAMEHL9$Y0Y&yZf3F~`YB zz*z`9jhoc>;FVj7@yEsxz!2faUR6#&@sv0>5IxfvqoQ82+6K}-g4~E=Bn7m$6k;|Y zLx5lCyknSG3qIpxW>P}DrQ-Q+(t8%rcZB)7`QJQ1o+T+sPG{n7F;E|G$sn2&TAqRp zYD1sIYLuby5ltC+ZwXF-Z@=ac!8hf1%}7fM*+yhD*hfld7)(xMyNL#m3mp7NlXMtM zX_g7rzA}+`E(@z+D^Zl1rx+GQi+66X!t-XpjWg$WV8hY}Pd^iji?oF0-TDNBtEkNH0#YVT0m7S)&ygSQ!opJ0N6SJ?pbyzH z{oRKL+AhE6VF{jASY*hUy%+8_U^ckgEAR$O$qTGydMoq})k?T9v999*VhMYe3S~{m zT5ea9WBDj(=SJ~JB=1N0f^pbs42J{gp#tL3O);Zf0RHEj27~-=DXJ0|W0ioGkgI@C zg3y;~dNC9(>^OEAvuTzNV=>L+LE2X-ayIR;oYSCI&bPsADgsA*Ye0}xjsh*wvuW3E za98I)cQKzjj|>|M;z|5g`0&<-FtZ~bP80bSA8NC02p({YtG9QruD!a}d^dQ`xZQ7J z#qTpjaDJYh&{L^(AD_mfOYJTqu7di4&b*((`Ubkl=8}+P&lL08BEAuv-M>Cv-qu~W z`siG2*uRxz|FE#_Se+iis*sP-b0cW!=(B6%oNk2L_E*+VcmFXI>+Mc|ta3tzA0pyr zd_O<7J~322ox`3h>wEwHU$d~X`~fr}5I{fyIKK-@{>s9-SeV+H(*Je-D*=0^Ic2}f zhSr6+^iFtmuGLJojBtY1Y(rt4+-$Liz&p!kTbC~)T$GF>8mQ}z&5(!dhF!ag&=&x* zYMK7ZPTPDQzeGZ&Z6d?|nh3H!jRi$|;vG-0>HYK|ylBrOSLz(bET^&JXuZg@*mE2r zE6H`ydN1B5HRjqXaEzvywiDOUy9TIxe>7j5$%$|b!mpKo{B+VJgmj!a0aP2`Eh$Z8@g!4y;&s#jd4F;(QypoQ- z@N3vC#rBx+H;#5@Pv8fw5oq)Ghvml;LlXUX&&gNYU!)oD^Vi$8UUq=prag`acodbS ze9N>R5?jHo1$zQ^VYr$H_htBm*LJ6fAgfKev>T&w*^;U?v{!#U5fEttv7nN8C5A^B zxxxT)fk_tfVZ^vGWhb~4cDPy1IXnR3C7oYiw=5!$H-^P}1oq2i75T`}c5)1j$PfTp zPZ$2m;TVqrIazY1!pTSjufU~RyYuOB)&FC|`SH0WSC99Z?&5|x=ky`H+wb)%o?rj) z)1Vf__Q3s={@dHj0OID$?HF_Py@Ik;Pg=d9vX`IY6s$-+YIOo?Q8LFU2O%ap(27AO9HT->a_f|1XbZh1B9Ir2nMSb8 znYVdJ0&Bsf zEa}842;Bw{5FxKh;RYef(VgvJ>wh_4EMN82kJby@+4&x zBvC#sgDf5LOUA`+)FhJHXV7x{2v4C|>D1St5=a8AA3slgz^&}uU--B-CL(TaxjOSU zIvm~wC(a8^y)gT%>v_$6lg{Lme!g9hc`tVO+zRPhF%P@7@u^qbnj9MWic#_+Q%A+O zYSlP@Nh}ezP{D<6%3QPAz+lwD&;|u%pGv5AWFqe(CFYBq0l~OsZMx06?!C?8h8;Al zs`)xkj-`KD1fppZ3eyOqVO=$0^R`a}r?R;L&t@>`r8f5m) zR>C4XgA@k?Wx|!jWZRW=Zn!!`bhWpDY`sRgX>x}gO~5u8U4x0UcKW0>F!$os5I2-E zXOw4u2W=aZC_hHF8DrP?! zj;J2A>y~`v)P(E&aHVi27Q%;{&=O%+1eA5DEKaiA*J_c!doF>|a-GB7Jvn61w)As0W8YWpSpE;;SS0E5oy>;uN&bpAbS3(6+G+ zj}D0;B-xQ;PnmfT-!xj&GR;2HQul%}RXCV7dF+pVyOs<0<_K{OURa}?bHr%vQiSX}#Rzd#4|ARO>I z!nOw;#nOF_D}8Rc=^o1r&7q92>RzQK<_|>n5$noP$vJ~m>6R6?OQq8l>#AU(rb(3a z@pgL#B8$1vNjR&dU(ImR6Lea#R_d*U)5OT<5vyi#wPHKE=6J0S_%FZ*uBVTy6CyuD$ffP=_bCTZnnKipOte} z%A;DJ_LM3v-u8Bokg_QZeV6PSy$y@kj}WN+x);kE3v1Pn!xbC&&%^~QczsT|%wf*l zaT5s;v{Gv^MA7+gNMF@DW^Yb!t2fV@A^h$w>tX^E53dyaL3%4Ze!j#0x2?m6mdCEX zj|#{RIv^nUe*`UO7f%~g=imEq)Ph7?6B~a)MUCc@Nb`BjE^_8f0M`r5 zp4FUVM6CPvU1LtznFxwRHTehwE1-?_9=(FHtcvkPAmnjw`+GhgB3dS$FT$V=h*Ey= zn|5y3_0SG}qu6>_@D|`IK*xen#g?PCOgf{t$1RU*d4~isoVUyG<@Pk!KUxprDxw2H zJF`Ggi~HmNc^Y6b2Ns7U%OoS;Ig-4bq;L=czNJpouGX=}5q9QZA1DN|+%r!G`}aGJh-)3NQCX=q>0q$xLr zdqyN-*_Y#@p--VWMa7_7JUi{U5O%QDp<&xVLg+)|1bx9MuU-1|0hYcIo8t=#OCg_=C}mW)gg-Pl&Qhnw z=iI&n5(Hn15lgg379zf+oKpkZ~+iyG;kCN9U1gA=|65qmx9k$)IhCJFZ-H z-2h{I!mOE!$@bP9OlTb-#MHoqx<=xIFaZPOMF48dYjUy(=+@8F!Ut*lvtNryorI3) zn&L001!_0Uq;HpkU?Gi-3T{%BR6#PHZKI>ha1P%WVYF!0ZmHA9eGtdc5T^4U6f=~? zHu~^HXU+P&@yNBQzwwxWD)m7*aU4lNXd}Om1|!{q%AM`@g8WFGx2Z}-t5z2Mv6a61 zmCkr0*`hh5XP`@h7I8GBsm)$63S=M+GYUs^Cpc1`&+vt2ncFMgGiLpPE;f=|m%xzU?>l*S6N|)1YEij=bY3vGMLGMIZXIiytY^zF$o$i|QSrDM? z`K+?C2{v|C*nr=p5|JHhc`5`oN;&>>HDIc7eF+q#Ll7CVKKx{xMwM;|#!b_?$Y zd2djJlqvk#wU4x|)QM+qrQ)xkpbc%GtnZy=%O`-Rpb# zfJsI_ps*T;SoXk;l)hm^q^%I(TreIL*yN=*ZzW#kr-t627_D8*fmS_**X+w}&WT_J ze^`lPmdd3iIwt0t&WBKKoDHL}y_aVvFeJP4IgKDNWrx*c$M*}EPE(#63(2Q1rQcva zfJ?G1*B-9Cs|5~S_QTOM1B^JUa!AVJ zFWTWR*v09hJHC%9b^E-%To4c_*>P*4q@(&z3DOQ{RVNkdd*(+(b9Y@Scre3Y8AjnZ zx;(xf6c>|sclRmR-x$1#1N;aPQ>2m8zP|X8RHI>E<=|uucS3J{LV8h8i_tilYAM77 zWUe|k%*>0gi*M=9qqzjOWO)WK6Zbd8@iJbUjTP$%ZjZJ5X392LGShk7DBg0gBxA@eJlIWE|HBDF0K9!N5%J^}Z z#kZMVtv|%mx2D^|&#-sBB2ya6?r3ML^QWef24rGD^>SRf<4+^uU2Oe3b%j`2O+ecv}BX+xhjhF@qy-7m2A z{Qa3zm$P9U-O5k{{zjn_4}S8-4%eu&`z=2rF1x#+X@r;^VaT(;;==0y;PlHBAHRNn4Le zrxF$q)3J&DIW4A&jg5#yQMn%mS{u0(AzKCs1xfGIzeiLMfI*5dZ{2OWW}dBuHi(pd z=GYm6Y;!?@8pQtM*Y{Xj?%GPTjB`?Xb>u!H;18UD&QCg4IH;6lCjCyA1ORsvE%53Ex!9$ zMT@tY#soV%NP-u?wLHXP7Hp+N*C9r6Be)zx=B3=%n<&Zi%-52hvQUV|1!mX=aBM}- zwT-SI!u#5Og8N|1GX3-%n^}yFTzVbgow)fFl}u#$NTeqj8Tr2b;Cl(tZA#4X20?*| zkT26cKyVNrsPy7t1!KOsJ0ckhf>d~bh;YPSYlE$k2D{I5gUNs3fCW$39eUI7qLvhs z`sEul6Md%_x~!F6yH^^>?T=RwXDS8~kwohVS`F6uuI>>G4b3 z5s9qRxZeV%*68B0LHJDKFJ@#bmk(d}(Il6%#hJ6A zwe29O=7gs@Kaq#G>fD85WgublV`A{*XNQ=p2~rM(hM>W!@N(xY?4JlEUrA;dPioLhTzr%Gywi+wSt?ay)&@u+%!3Uwc*LGL&85BS#)tr_av-C#*%{|3^b*_YN4;$1cmS=| z+=`na!~_VqK?)+oF5$c5#DlbXK*+Bsl`i0Pi~Nh%J6dBnG}gEZ>4XT?6NuatM5-Guc72^-G5D3W)zbL<@P! z8{~GQ{8#5iYt0qgXA=)|2q<7D^$jS1UZG=97)VXrdf!V7^ zwjA;G14Ylo`I&tiysOqPI?|zAOqCrnUtt9}vH*)55vI0l=!X}3D1aED37bx=lmH?%CmaHC5SfXAPlu zZn#Pjkg$=E3XYdrMVyLA)hWcxsdAnJnmwpP)|f<*uX@b8QjSPCps0+XGY*irtB~! z*Sj6*K3N%bVY43TKy$_i;~Z5NinX8Kl28Fw%^X#!7B7u4HY^;VoOw+^{PY~sWI3bf`p)@ z5j=q4{hp{}RvOrZ;>Dj=^~blOh4~jPUDj4F3gI&jpco5DW0e?cd~YguaFl{)EWX%j zu!CRq?h_yv*i_hX7yME_m0~g+QeiG3!UM)NFe(Yjkssm#3-CaJE$7=@^+!8;$J{b z?mVWBi2du0VZVBn+-AS4n5>qoyo|ifTDs4-Vd3~m9Dmyx1B;&L20=y9Ib%pw>9Zs% zgYfu_C8YFG(nW5P*8C%Z8fc)3(qeG9!H-zkz11T~E7))8_7ugdn5~K4&t!O!HTCIH z>Ew>!JR)yQR=$X+J6wS*dFCc(1i}1PXx{02Z(tmgrFPYk?_`>JKD0&}_}aib5Tn=9O+T-F}g{K8wvbQL-^ zwR$--wR+~U`IKP2+z2ml%{6{mXnpt5MfG3Ggt={*qm}M(-ZE|UcDReOuz5% zJ524fWj^zi;hG^N(#*Akgzgz*TGU>8uh4c2)^VJyp+VE~BpCjn>-q{RCnps-l%RnQ zTNkQG`ij-(*S}mB2VIuHcd#rO>B%ti7>zq!S#D)}r4QLiFV}QIv*)WG%*Csu`F0lP zOTc4S*gYw6H5DSsnP9+IAi+5-`tvHlNbuDCF2~vz0j$J!eC+z}1Lgi_q4dla&nLBy z+53P20a5%z0uCR**TvLH+0@15Hv*>r<1-_jk)_?4@`O~M0Mc7Ca-GL?VL0(l8D_q$ zvTeL&k`(Dkn#~FCY$$|KeG%0|FneyV@@7BgFKi$1Y!Ps9Dl{Gs2Lto2?9FxT!5%OW zJm9#kd{}&67bsW>G>HiM+PI~(=GU0i65jlt>Hgj7I%d$mPY0EPPLnJ<^AYwO3f6B1YN9gj>yQ9?A#FXBW^>~zT-!`?nhmUXCnoxS7w1xMA$4NJ&mjS(Tz z7L*cTYWeHlDf27*6nZbQMs&sJnADu#l%(=fN}Z4Z1ya{=W{Hc;o%l1!Z3KFYK?m9qKC1}6On`>> zVuIaXEbdTSk%KnTHhwO+?yH$D5LYVBEC>4<)_q0V$PELO%aixkw z#VAb5h#+?wDXXDs(88b!nDN8{Vd-6^u$H6dXTezCa`b9S?-J_o`4{3E0r^=tQMh^9 zw<3+=P75Rzv7fbo%&}mQ2xA8WF}Db6fXQxh;j5S&qSnqncl_WxPngi8xI3?!^fuOA z)Z?`>UU~uc>ul??R(Ew?UW)>jGM0NG-D)h%FG8A<5(dX~%R2=m2xeQM zTAeaK@0r>-Y!EkeJal4ylVWFnzdX&HiP&|uZGbRh+CaDA8P$Z4d!B7I?U}^1ztgXy z$#*KQ-w^C!OIWH~^CmKzfsC*qG&R{)>QRd@?Dd?bE>*=zJd-H%sYF-8NncY>opIQ? zRfR`*6wD!T)F5d^8GWr~H394v^}Msv0_+}V2aHgmG@=%XGz!sYQ?9aSW+?Ox-P#un zzzL#)jt=r_3VLG4!3j!?s#8O$u*am9!GieF`>{*iESXJ>k_vhxL2-P?lO83kxeb;f zQ}YI>Gztq85uhtU+x@yNjQ#ut6;;c`j$FVcB=z})(02z4hap@ z9So<1y!0nj`u&08!@uJT$FJ_byxrWMFW$Z$(j&ICOi^~U9Rs@czC3YJwh$TO0$9(P zvcp696`|s}*J-03r9>%@ahtg}G5WEqm{%4|+Li2}_l>8V^8o?TZ{zz97AXV=H*LXR zx8xyd|4sz~gV27Yeg69&ApFm2{?GNl{2hXV^uIIs_txzHA^d&)_F*#r(y09>;h*iQ zf0K@X#D+hbSN|mb_x`xQNr8aA!2Cu0|I;n^C!ar?rvBzM2KWCx#DBC<{mJFeP5-~S zC=&n0<