From 3e246f1de6cbb55c7bc492efc0d1fd210d219a19 Mon Sep 17 00:00:00 2001 From: Robofish <1683502971@qq.com> Date: Mon, 29 Dec 2025 21:16:17 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=8D=E6=A0=B9?= =?UTF-8?q?=E5=BF=83=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MRobot.iss | 3 -- README.md | 2 +- app/__pycache__/__init__.cpython-39.pyc | Bin 137 -> 137 bytes .../about_interface.cpython-39.pyc | Bin 11162 -> 13368 bytes app/__pycache__/ai_interface.cpython-39.pyc | Bin 5288 -> 5288 bytes .../batch_export_dialog.cpython-39.pyc | Bin 0 -> 5878 bytes .../category_management_dialog.cpython-39.pyc | Bin 0 -> 8529 bytes ...ode_configuration_interface.cpython-39.pyc | Bin 6263 -> 6263 bytes .../code_generate_interface.cpython-39.pyc | Bin 11359 -> 11421 bytes app/__pycache__/data_interface.cpython-39.pyc | Bin 21715 -> 21866 bytes .../finance_interface.cpython-39.pyc | Bin 0 -> 34247 bytes .../function_fit_interface.cpython-39.pyc | Bin 7765 -> 7765 bytes app/__pycache__/home_interface.cpython-39.pyc | Bin 2070 -> 2070 bytes app/__pycache__/main_window.cpython-39.pyc | Bin 3759 -> 4599 bytes .../mini_tool_interface.cpython-39.pyc | Bin 3763 -> 3763 bytes .../part_library_interface.cpython-39.pyc | Bin 6960 -> 6960 bytes .../serial_terminal_interface.cpython-39.pyc | Bin 5838 -> 5838 bytes .../__pycache__/bsp_interface.cpython-39.pyc | Bin 37841 -> 36084 bytes app/home_interface.py | 18 +++++++--- .../__pycache__/analyzing_ioc.cpython-39.pyc | Bin 6849 -> 6849 bytes .../__pycache__/auto_updater.cpython-39.pyc | Bin 12432 -> 12388 bytes .../__pycache__/check_update.cpython-39.pyc | Bin 2419 -> 2419 bytes .../__pycache__/code_generator.cpython-39.pyc | Bin 4007 -> 16273 bytes .../code_task_config.cpython-39.pyc | Bin 8495 -> 8495 bytes .../finance_manager.cpython-39.pyc | Bin 0 -> 20849 bytes .../__pycache__/part_download.cpython-39.pyc | Bin 1710 -> 1710 bytes .../update_check_thread.cpython-39.pyc | Bin 1244 -> 1244 bytes .../__pycache__/update_code.cpython-39.pyc | Bin 2384 -> 2384 bytes app/tools/code_generator.py | 32 ++++++------------ .../metadata.json | 8 +++++ 30 files changed, 34 insertions(+), 29 deletions(-) create mode 100644 app/__pycache__/batch_export_dialog.cpython-39.pyc create mode 100644 app/__pycache__/category_management_dialog.cpython-39.pyc create mode 100644 app/__pycache__/finance_interface.cpython-39.pyc create mode 100644 app/tools/__pycache__/finance_manager.cpython-39.pyc create mode 100644 assets/Finance_Data/accounts/7751771f-1363-4606-b292-2db511004bae/metadata.json diff --git a/MRobot.iss b/MRobot.iss index f2ac647..ae7d594 100644 --- a/MRobot.iss +++ b/MRobot.iss @@ -9,9 +9,6 @@ OutputBaseFilename=MRobotInstaller [Files] Source: "dist\MRobot.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "assets\logo\*"; DestDir: "{app}\assets\logo"; Flags: ignoreversion recursesubdirs -Source: "assets\User_code\*"; DestDir: "{app}\assets\User_code"; Flags: ignoreversion recursesubdirs -Source: "assets\mech_lib\*"; DestDir: "{app}\assets\mech_lib"; Flags: ignoreversion recursesubdirs -Source: "assets\logo\M.ico"; DestDir: "{app}\assets\logo"; Flags: ignoreversion [Icons] Name: "{group}\MRobot"; Filename: "{app}\MRobot.exe"; IconFilename: "{app}\assets\logo\M.ico" diff --git a/README.md b/README.md index cad5bcb..9d2722c 100644 --- a/README.md +++ b/README.md @@ -86,5 +86,5 @@ 使用以下命令构建可执行文件: ```bash -pyinstaller MRobot.py --onefile --windowed --add-data "assets;assets" --add-data "app;app" --add-data "app/tools;app/tools" +pyinstaller MRobot.py --onefile --windowed --add-data "assets/logo;assets/logo" --add-data "app;app" --add-data "app/tools;app/tools" ``` \ No newline at end of file diff --git a/app/__pycache__/__init__.cpython-39.pyc b/app/__pycache__/__init__.cpython-39.pyc index 9dd2ee62372c23ecb3202b7712bdef17bb221f6e..121d291e926c8717e27d7e89001187ecb799ebe7 100644 GIT binary patch delta 24 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 delta 21 bcmexv@ZEqXk(ZZ?0SLNF?`Le}$(8^BNk;}} diff --git a/app/__pycache__/code_generate_interface.cpython-39.pyc b/app/__pycache__/code_generate_interface.cpython-39.pyc index e239a45025e6dd10f673aa1ad1257a730ee0040a..7cb682c0d5aed08eb5bb3260dcc94bacf5fd5485 100644 GIT binary patch delta 2762 zcma)8U5pz=67C+`K>E@{hugAOw=V0LmqVuzLr_>mD43@z3^5 zepq^NhyihT$z`Dd!G#1b5)TPS2(p9_4>l zwrX@#z8Bh*S_|%6!8l4I?e9X5XcJeU96{Is;A=I<57rCre&3iYI99b#v3OQCjBE5M zG^gd!wQ2cpV-3Aler-IjkK)D~(CtqMdk|Jc#^wD0O%(P4EZik~dajm_Cx_?* z@}=ZXa|SK52oK5sCU;If3}P%2JvXr{+$`XjV5Lb8JkLof) z8emp~dvqnVt$i`|WdP29Gd-$z&ToH~eo|{xaaRqY4&aBe+ID%4&!b9ZbQ9{0YK>RW z*2xGH^h0%CuDZT%9f8t0%ekQ;U|Ur`e7L}?R5y2(ug+yo@d2qL< zGlNB*B0}Frn$**U?i`rkEp$d3gTxDi5M}1m+8_bv3C|GWQ-sBYaf+M{w4yA|VsL0g z1X`wuEI~^1Pt5P$N0=ETLDCFRQcYb&ocE^)RsS=9kYE%Z6P}m|KvWL8Q8*;74(Yfgo9HnK9;Wh`6lRx4s;TiWz#cn9;WKv03RUc} z6P2WwpakSzJ5}lNl1g4>_f}SUDM}h5(Mk()AS0r1#~zVv^{JH!t6q_6^{W-$e-%rM z9;i!3^aA#YRZtz>OS=OH23fy=7;JzIo(NL1k5rEZi958YJ*H9OWhhzL0A5)(#Io+N z$TTVJ)WClj{PSwV3>4GLJdvsXvGX|vg>^?Dz}CwGjIhyP1h{-Ze2o}qicCSoJtQ|K zU(H?_(}B)ouz&Vy0=_EtMU6_?FWmNZFjdQjz8oN<1cH&H_Hpd|JT*H zJM!Gf2%V9ij@)wls6SAs*EhShn(b^Z)|izqSyhV{+#2WD+?R$=jhvq-S#G}IIF{?= zk*5yJjiZ03C*^yi6X`|ppN%c=xAJpN9cc2~(amdc_V@wKX>SO*SRD>Us=f|%%nBJagcMX>h3Eu7`a?nrRE3mTwgEN?1Po+az1#zTXt=W zFJXY!5xP>j4s`RFO8edQ$F(iP=<*7}DTIF^yb0h(9k;+;=WrQ*VgHHRw-AmX;BPHI zFGX%c<5d*jMo?wNjQJFTnrX9BM3sw*j4@`-x&?H#KaVd@_%cj5`O%^Jc2NZupMC=!ZZSs1iuXdzX*;cP!;y$`Fzm^ z3PZ}w=U2pEjV|K|{QwDg9Be3qCZa~xm^8+XwMNO9HVmWBi12=S;~!qRM^&j8_t*&d i;?v!V*kJIo@tEUB%Ift4Uu^J%6-TQ}j>~H{Zu}8svw3F# delta 2656 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 WGgdUf3lkH;)_Z*S!0d$Ks{aci*Z?O0 literal 0 HcmV?d00001 diff --git a/app/__pycache__/function_fit_interface.cpython-39.pyc b/app/__pycache__/function_fit_interface.cpython-39.pyc index 886cba0e05d5bde3b130b40825b490f3824aa4ba..66edcfaee1b71cea5fd320074bc82123f590e14b 100644 GIT binary patch delta 21 bcmca=bJd0?k(ZZ?0SIruG diff --git a/app/__pycache__/main_window.cpython-39.pyc b/app/__pycache__/main_window.cpython-39.pyc index 8e971ac8d207c48ed0c5b8677831aa278c6a7451..a8602e45469a25145611105e4f69b6d2a2fa30bf 100644 GIT binary patch delta 2480 zcmaJ?>u(%a6~A{LyR%Q*vAyvt&c=Ce(i$g9n$U(4$B)Fs_WH5N%7wDp>>aPi%p=^H zjT>v1RqI3ngaz$a60V+T(4=G3~t>}M%g!ne%V;99z1$?Xc#yPW2Yyx6NbLZUO zJ?EZ#&pr2desk!vqv=vA6({igX>GxXcDvqVv;2@nIa~cils6& zlw~twMOieI6;rcfEJleQikfljAnOTb4dh4_jH54ds-1#2R8l zp`134TF2Ni`WhOyna8aY>_j-wZl1JGu~VVkVdkvU>@>*W-aNz3TqFDd@4QENr=Hx9 z*$Z4h!Tws5JsjK-U7gBFP=O&>cG>)%??Rt;D6+K7)?*AoPZ)}koSxtG;YPv?Y6du{8+mJwj5w8t52qW#` zNOYTe9jgbpwy99!bpqanNd=nS8w!LW15#%7;8qX(d$(ygNB34APaw_-+HQj-1}m4G ztwvx?pFIB1|3Ew6jthM9=wb6a+s!wA_~g;M{-@d(8Y~fJ!_}(iId-m}wUszutlrw& z^98U9f=+a3Gz%*1R#T*7X2dg|)J=tBQZaTvORGBrDy7aER4uI3Ac{ERr@Ux~j`2o4n8 z(z0IkoJz%nAEqvg!6KIoUeP`AzmDVtO!EqSE*>MHJyH*S`ev0b+U|c4zt~V5oA1BVy#M&g$M1jg;ZK_%z1e*HxC}PWo+wDjT#N9z??JQ9!Cixxq#pV;fx7Cg zgOux1jc!0%6y^2vp0Yvea!vNs)yUT+aT)$mTftsk@wA%4Wq6fMNTVfElhDT2TK^G1 z?5hg#Vt3!Aqz*K=ej4r(5MDjP)mr2Z6>m4Z1dr6zACaF(8{mA2+=QH|tKU@ZcaFNCTA^(I>~~Kd{ru%@E*Z$~T{n;nM_d7=AmVyl7eaJGN3=o1l=0Dp z8%&*^x^}$~a!nAMc)hIOM$cgEi9o##?z~)7jH1yMG>SVWFSe#)sd7~a-S)yHYCsm* z`dTZY0t!9w=7^%@R-U`zL1JG5F2JNN(h8vx)o4`5n}g3q zBO+;i>xcfY>oT5X`1m{VH&2Rjki{f4zua|l4T1lpnF4QVxB+nkCDaa5#bVhk zxo%lE&0=xiLc*!TS+k&*fzQQq11AvEI<&aftqp21fn&KBgXG-ZdGEsTyf@|uT}S{5 znUFkbg*NeY^jg&rSg3-wr$~!aT!E|!+jF3{yzZICErEBKrN6OkR$;SiA@jKYS5lWM zVR~X#3nU!TjSa4jrLi~_Asu(C6S55Jb#-Bs%p!nLlt9=U$Lhs0w@bn+qC>b!`v&{` zf2O+n`%$G6s~NDNv)_2YKb#(FU{zxsyG3iCHL@V^`YosG?L$M_jod1^`b+1-!0n6n nvvM40mo0}^P5o6&92bwhizaDONBB8nOEFu|TiG^~7$MLeD8A&#)97bCF{>n!dW#K6cg zX!HPoekWvOEa4@|vyQbNx^ZyNkYb1pzJE{Anb-^rHt zjhu~G_=en$TrEC9+nAM^Ncd4 z{3AM2)BzIHcf_XKqU{HDS1^Z1<)zr_*tp7i6HI^~1bBx}C_gloLL*>?<(IJ3X3n) zcp~w>yq}oeZ^9=2^+dqifD!IYKowK%DTXPLYMs9UyoGrhK3xZTEo@-SGTYmt_S`aL z{0;*>zErW@*2xV`f=m(8)BC5<8CPEOdlux2zJ$+LUf| zwoV0o3ziHb*H*3({YI^_9B6{`8Q_S%SX)}=Z!2gn)+&|x>QZCvR;{vD=TnL_mTH^T z)!O_LpH^;sb!Fk!{H@#k>;SldzEZtb<8c*1Ic9Qht^l-!H4MDsryM zjH^xZd1X{$kZClU%=Z1J!&sxy_4DDXVS@}p-WeFax@iNa6Gq-h7zHE2Rm8G_^xC6! zF+I617Tet68jxJo4M{2fh6-HoxLkE;ko_n1L`I)S6`O3fp}igo2CWoRGtG~;SqBdI zAQamVFGKF<-YF}2d9N~sFi*8+0~GwbH;eM;+%WEwI6rV%bto~ZE$ps@vx@9hz1a}Z zoL!NAS;>#K&Z&6T-fDM5S1c@x*p}@(GgINAyL5UjJk-0_rXA+Y!5=>I%V2Uijni5h O+Ib4lB%tosi2McK2x!Ov diff --git a/app/__pycache__/mini_tool_interface.cpython-39.pyc b/app/__pycache__/mini_tool_interface.cpython-39.pyc index 79f3a2aeb34bdabbf2a84f429fd0f01cf04ac0c4..a8c9259c05ebc5fc46fc0a06c9321c90bf5f85cf 100644 GIT binary patch delta 21 bcmdliyIGbek(ZZ?0SH`e-7+`wEaw9NH2MV9 delta 21 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

kG;Qeg(&2 bgIY(hP^u<1>HkoN#pq~tL=1cQWnS{XLhP7G delta 13076 zcmcgz3tUv!nZI{tm>0uC5acCX#0R51#kYtO0iz=LfT#pBj&lbX9cJ*%AV>yBgK11+ z)a0ajHVL%dB(~WmDQ!1>THEe!lIGDS*>-cg&7+NN-Tb!QZrU`zY?|Hge=ab9L*o8+ ze=EQHpY!<6cfNDZcfRjC=U)GGzu~8k8Is*eNp^|;J@UJEyY7AS&g4A#zB`vZ7F8wH z;xA|`P_3%%q|~OUb~TZH3pYusLrppO--lY z1?p@ygMJsPnd%(+U8H8I+4Nhi=BT;!>s0g9x%9i3_~fev#HYYpM0}%5s6bH*si064 zlu&-2T15FGkuO!}s|%=M8I>DvO6`_X zd6`;H<>jKhO112goE4Wb6;7Kr`jl*vXFFvrX=70JZt@1a%pDH0CXazXePepmNK~N) z0##NGereDUF$~M9F=9Aq7%>bQRg;=RdjS;zLp=utH>!cz1R_PY0Lsl)S^`v#s zM75@fDI$#+s9&4AN0uaIJM)IT?1(p{xcz>mm(r!Gx5F3kstWUV`htOw;tMF@uBcZD zc>5F&iKZNIhp0M;Vy_bPtD>~buF$`hE?-FL=nZ(n)D-MOVB_sq!a;?&s-Mt9jFsXh zLgwx9yFJvNI_Xw?QN6cu8T8(2S!ZaC=ofucolD49911h%8j@v_%${H%>_u3k_%z^-gcNmqi1UdLsVQ*!TIuT}sc`T*e<|nW6|$8BM#?G_bzBeQ|qeadGRe z`kl)4wWVzprK?@az9mj7yrzEB<|g`WUtC^Xws^ghNTbMB64W=<=`|kk8UJUXgqfaQ z^n~&Wd{RW(mpLd$v#=JvE-8|?P-CrwN1HG8${^MpOY?w*<)qIi!UX`pm`+%8ff7gWeKraEQS z{-DS057m^#+G+ghlFVp2H4N1dL?n`rr&GeI*juV%r7`TSnZT-V%E+t{dCqu2|+u$O7Z zQ11aEvyLmTW*t{dwgfU*dfZ{63$VqM(`740NtSn1hFPv~KSuyjz&`H0LK!^ViPII8gubxb4Dpm8^8m5Kg_ zjItC+t&~EmDkNF_?IjE+MC6EZ$S^1qFSFohA-f~PO5I_Qr5eH3tQrK{9KqI##h0Zk z7@wQWSS1a2TKMrDbD}M@a8_@>FBEnK4{35AnNUM8q?u^Kx-_$>pj@!W8^A)kRWWkS z+U-8%Reda^SqKB}Zm*Wm$7m^>CRR;jXB7mR+`%f5!8Vwr5NRRz5w8n--PJ<|N*K-} zA_*lENU}ptl^4o(Lni&QIzHSqm%n8=%2N(!@PJV<*(0VQez)<)G`1FO(VJ#E81w~L z7B4ilCT>CLRzM>^VJcV@>zHk((lUDVB_%a9G>W_c^W z*}QwTc%lahlmKZm?9&o;pspg9umiO_n3`_MwT* z7uwk6_0YVXm)R~VnLIE2O-qK{%KvQHB7cQ%u(rut_=DErz1~o4{A?TQ#K6}fmBqK%mds&wAa=OKY?CSO@O3&ZBXpKp&Sp4^>Lj8jY0sa!&*#xtrr z?4CRW5WJTlKu-u8Nuu?)bC!5EI!GCIjG&>#nHYE2kcdSASgDveOw7EU7He$kNk7HZ zp8(lS1eyuLO&4S*)r9F0CW{|;>}rSZh!tgGAtJ~^Tn17t$>s9+-Jy`jOSaoJiCZg3 z6hJ*eDLoV=LsCjFi4=c$Khla?p)qU0)5O2j(E+mmzh5U)7X z*|qc|bXZ^NF&)1vxoP?$iP>lZbu&O{FqBcq>a^)IFlnEl>NddbfYX3G04)G90--Mo zvX}=9J_I)*>3fK~Qc`65XfP$)khz;m* zbChHA_;BWOtMJds>|XxM%~Y?ZU0gVoi3-xe4KC1J7Ts)EU?AT<*93LqsGK-E_i$wAeJX4uR>)M<@w30iYV_d zpqWQ7u$Ig7^7!feM1E#&#k>F&wK(n5O&{A$@eE8>XQ zhIon6v;xEWP+rSkKr^gI2t|KDA#g zi)Qr&Xd?zZUNIS(ql=D2e(yLLbvhB5ui=NOj{%qlLF-hm-L4I~#ZH-v$ zH$VjPDJn2gs!z89q8}41q$7g9_DgB))A>t9iM*s}j^`NFQS{_J;v)s6HJ!=P>Tc~c z*c~T0Kjy%M5>I%sX__oNQ=vTiXi=d&*?Y3L!6p{!i{S`64e6b;K1B%OTZJV1z-I^` ztmMN;!KAP+0lr2+ThAMA@%D##!-Dk9V&BE2JqaqvqM7vx&<)SGQT!c1yvc;4T|D~v z1;z4iC>IL?dI%^gNYcHskS*Rst^@4_fNmy`!Zr|VEoMuEMum%3<HLg0fo)u(?Bd z1Qa-=@|NOk6H0ldCqL?w#PMMKsBzQyQR5E7+3N-kVbgE|9rxrxW5ie|?OQQu3Y#f_ zrYny_39KYyQcc;?uw_J|RDzx|NP`K3=7^b&9tp$N5vf`_Tyn)}qJQEv5v6lV1ZPNd z6I)I)u@!(EfDF)m#w5iOOHo5rn$Z(Fg2SX+#R<;u4X|&Z1@^qtqFJd{M2x!I--xPz z1qdH?6e+m%%1Lvkpb#NX3w0ezql84KHiw)nPMi)oM=p_BGk>z=Zfzd^m9R6PA?Dg^N-YL+<)HP zg`yU^6jAfY7|m^>vF=~KQ2r^uW%-Jw&wic_Gjgb_Q zEc)9U`l==vEY%sXJV-XJ!+a_;i8jRh&pf3uYxE1X%M3KUf8Mw>Hytg663j*_1CR-r zBabeqJ8PJeh0K+s=Ra=9FNjU^v_2iwNHUCCH)R@2bHG5<&m`U2ap?xC_`a=6cxr9E zlNEewvub@J-r2HY876|xez|C)d}2eW^*X)bo~>)5g&>{>C<4p}EC7gbcM(#>04HEE zUQ#3s?la0L0eLg-mb9m zgKbQg+Y&o`e9yMD>}-%uTk0e#Tg`{I{qXvDW))jYs62y8Fc8liAzG;RetLxY7gtMb zt%`Luv%us&Y%t2awmG{vW?DZ4^O;QR8J@U1mp{~;w%CkLV^YUV`v$7GgLGlsv~S?A zH_w&ZM*q^R$m>n?-eHcop*Eh)LD)I$h?vH%qzw~y-D#E5IXTog5k^uJsp5TF7BAkh zH-#;OgcIQ;zjw!@ayGBonOB~JigSQm0=h`eM>-~?g6w&M$8=r2edh|=us_)Om?2H( zhjuj)n{VwZS|;>iDlfK?Mnw$Y0tdlRK?=OSuJfAJ@`GqS<^){}a@H_0MH9r|7sQ}g zLqI1J5v}Qg8cNpz5dX6EfF*!(Kq+9V(y?o(j4te8#kFJ#Y4~-m8S+N%Z_Sn8;HO%P z^ov{}g#wxker{)m`2i9k)WCn%+F-WO9r_mC^HyJXrWT%;{S#5PC3GP|(oDc9e)l7) zol!ZSC*}BkacsKn6XTD~7%aux`ivFssogD(J{Q1rrlS`LNVOQ_`0ebsK;9476sLm- zRlLT(xo2BLyq$yEnYYST;`bb;$3$ebRqSl5K05A%M;vK53BP!A!WyWpGkH?1BGxC(B_dF|07e){mkjiN^9+QUrT}6Znotqvc9y~m zGBZ_U*F7zu68kPTy_>1*5=M|r3H<`rj#n7`Qrkb2e)=)uk78x0CEf84w&(KquFuO5 z0*dnl1~PuAnBP9HNSM4oq43Xu*upEwHq&JOVbs_Ds6pP%Q(cS9!k)MBb*}TY&wlG# z9-Y`?4bD<#L>oKcdO#+i9e|POSAcgR#Q}E%ZUDFd`vK_yH{bvub{*_MRt3=LB>g%T zQ{Tc;kQX--_aSvZ-~qsc04v~g01;VznNnKH_Mt;{!!|sxJch!I4PrDy4`aGC?0q{k@v}M86t>=*g?aK~QiY|=yf#?w6`vA<$ zjF+p|aEIsDQDI@>8`*A*-be>HwwF>)6TQso4TXcO|TiBrB1;u&PWNiZHEijDucw1Ny&vM=EA_o{eNh;?A!25kpA*$FC-Ma8s*ynLd%66Mzb01k~4uW)6E_E1u=6ptykEZJx2ag zq?jM-ST7&pU+(amtr2U)GQDK-w1daupSe05ve}FG+}>4@0q25k!K$(aMZzeG{TerJs?0Q-V+X*%o`Ne~U`C_i($&FCx#9fCP$i!_r^e$b*R{0yM zply2WPT}iZqR>p(IOM+tUomtAf+C9lDp?+i{GafbMTOjL==FMnHgj`p%l6imwuH@1 z^rNenkO};0{e@5y1!B~iDSWiY+d^lKW8g0qV<)IT?ad@&%tiX`j(xh zg*&O@hy1}{jT+B+!=va|sds}xH{b#QJ1y?r=_ypi`Vh`iL0J>AdWWy;DKIpRd-%`( zFTDFK;oa$;#pR*52m!A@^gnm*Y&(Y6x^O~dAt)UBYowu9IP}Yh4-`?zF=he$6RpH( zMbmz&ePcAh%8lfJAMRZ+?tq``UA=o3)j3VQHfpwg_qNN&AGmyiGhB@J!Y5w($^*Z- z_Zye)fBc;bBfmNEB)b#bsdDV?Kn_xH0+;Ur^aF&uZRLB9IHN+z_7J(S`VG#i|6kv( z=u$fP1i#|_{THvo->>8CN3SnBh-MzJil;5uO&hp&^!2C;5-hL&E=b&bMp1@^rGP=0 zy{V;6M?9~t+3*S0#x9><)uXsi_VQ!KVx=&e!bF@xuVU~q|9%U~rp?6#5_aRL@5W5I zX_9|u2ZST=nNV>ohNL{UjAaFbE@M$KUiQE6YxBLX|T{K z+}-WekM7-=KaO-iB2Gb`bxa{2wffi^`7{LrC4BhUb<1oK``EQ)A~{n>(?9}A312!f zy8{V|a^u1-c9wVy7zRrQawt?t=j)@^sOb7My1w!qu`t{sQt)7C&j6-|3*$EyvGEUp zNQ4XB7=-YY6LMS`I3y8`f+q05H}O}a^J#b=L{E|n9z5P$6Gutdt>cq3=9MRTW3ixu z-H(ag=eYgE`fCq^{3rprz<4p57-SS890&XgFikPw5bx!8p7?0to<9K02cPu@%j>@SmJ4oY#ot)M0B599$6& z_P9H}&+zn{7Z~W)AGh__-P|$$Va&B?2w$ZKqzPazyscoSjMu)*-@SQJG?}uA^lYRj z^b;c0KZXp`r_=aMRmI2FhVc(1RU(nj}`_bh&`RITw4bnB>K-ra) z4@zoc#6jqIXzY@0FMZ+PG3YqvIP6!G@LM54QZ+eZBC?c70%2;zLO3g8CQN(CHkcH# zkw{;QB&q4@Z2C^vHX_fFXf~1}Rw{pi$}>c{b)r0ptXU>scPh7S6D{#T0%=cK*FbVB zeau--X*^|JEo>E4>R|<(kCu$DVS)j=@E6BN{S`h!)LuJ*QheznKcUgDP^1Z zi>L0AU*!95ofEy{%LHK=nuv;R0Mr6-qSMTwuHLZEPp^-IJxB3Mmi0nY(Y+o-3QKt% zvIsymTYbOB+k@}y=|%@3v6g^c5Nfl9m`7}it~MLbz0JnUZgX$Ha^r~qUm!jhdX zAy^Q}G@D*IXVQyjhrvXz;>P|AbWLNh(nrMBvA;Cg!7trb-3~dXeNLb`@Bx|6)9np+ z1yy!GhHwgGF#%$c?is3m37wmXg6_0T2AQGExs0{*!P_5?YFX}{p0Y4~SQRS6r~MSl zj{Ua?{p>4D?`5z*hmMvYRRyR6)B|n>Gy~oTd;s_m@Dbo+fCyEmnImzt=bC1e?m#CH yaMEZdj0k=5)*V!P{oWcPkV4lGl*kpBOYt{0cLwVmt3942Fqacc$SGOzqr2F&i zo^4(Be8d6*HZn4c3588X3Q*Wda3FGsiRNXC+D`lwEH2>P>i}~IHS&N znGr@?p&v9t&<~k0=(ibBvmKt0+0o7!^%n(0H6qVQqn!pn%*7krF!`7y&o#6!ZsIo) zxeeB*ZSJ73n*`l6LZ^fpVK}yUL*V&P7Y=tL3A(?P(i?02%fzcoB$8>}vJwf(R%u5u z%^j5&$!1p#wBB_GFub67!b}!yeJpKyN+L0yN}GwqWkP#V+SiUPHhGIX5;%L;M(oFN zuAJ1fNi$71Ag2{MqM1qA^lt30n7i1joaduVDuzQ}LDKDB5AGyg?mvS2>zk3$1SGD| zUUz?JN84WH><8izbLCR*Y$zi?hJ$@S3t#0!k7Lu{o_j+bEI*0;Cy+daBmrb7F4M2W zuczeGx;>tw8BeyRE!)g^QaX3sr1UV33VL=rF8TXr3Jw96PT-IPUNmiAO%l1x8xKPZ zd)ECxI6h3mg5sWze6R-xXg`txAf7U&TV__zm{fvpTv(xEFAA-26m}nR%h7v6%mOyt z=l&}C+}D^fqcHA?R;p;m3ER>tdzmzoo5Xe2EIa5v*RZRMGM<8m%na&-Zc+eJ{fj~a zBWxf1TmK>)H%E#W9d44FB=fvM76{>NVNx`BLzpEFmym3EGBB@zgyirGd`YnD4ABuT zaBuK4AZtj5oDP;mBY;=pB3~{^jyM@|h$G>hFv7E9Np|G<@B#-5*E{m0Iv+CX4QTZh#C#EWIy-RsZtP(X`+7wLmJTp z!i{i-EOH_@Bakxd40BG9UUBN?V@?ov(hQlQWuP9GDVf zK4_Weoe<6d!@}@i&$z9?1z9KT)GvsHJ9=e>LN4351AJ(GV>=i^xH93Mz@4Jg+HgN} zgucRh?QD0TnsMrk*s>Fu5_EqvGgcVkhB>>#Xqh3W$OxA`AVP1BO#hW|C6#c+`;1n* z(@|##9zrPserR(dl>;erY_Tq|ID(6ffH{U-QctReJX~pQ=e9!&Qc-&W@A1uRXFmJr zqgxlQ-g@=DTd#ia<}W|c`m~!L-MIbArQ27YUYb3B`}Jp#et6^dr8B;8Ap-N3u0Or> zPKD9m-#@B8av(S6{=F$yE=Kp~j%U+3-AH98G&{FTqY!A^P_Yq3a(3ULyrJ7B9oW&o zy(sh!^v3yO@Q`KFz6U1EtnJAUB$H;|KKS`Mm=zbiz!6h7OlrZcwyCLS=zYL1s{3+T z8^rqt&FqAI1oEL`o=91CqMV!Z_~T}VVa-V(x#z}O=|_v z{kegQZdew`W%6m$1_7%8=2+HvA)TJyrTr84?z>^>%8R$2pZm-8?-nrg`8;q|+4thj zYqLx5zP5Dn(yixTy?O1!+m}Bqs5P;rx8DEk>f5`tWmjpCrgC(b7Vq}6Z7q*_3M8^T z-e@n7nKH0Ldtjjz2}qpGrLvxsr>U$>A1vb_%ZE{_rz|r888Knmx?Qj+8c&Y`@sx}{ zWg01J(e2n3b9poCg;Q`WiKOpXigmz~j#FTI0wffQ$%8f`S7xrZyugHMqi5+54q<|) z&8R;f^^@RUXpR%O(me^cFzg8U(`eB2fjEM0r(E zc%JZI$WkLwghnC?Ekc+?iA)p{1F0Zpf9R`%NJO$z(1;3;%!hg4v8UMiK*7!(%De4t zy${mzwP5p)n1vTR z(SBTE0LgcdoJ4Zib-Q{uQWj?8$iNaxS5B~ z&4j;bT=e~pO1+@ZOTd+2;q*V|rm}E{(&>u1jqc+5hsc}m?>EHUh<1AzT|E>JEniCC zVRzzwW^jEeWx>*r!j2T|RN7OLx%@O_Gt>7eyMq$)?y5$^o9^I-f!OM!r}MDXcK4+X zd&vb*{h#vZ1Qj3|iieqUFOY^Lh`Tt2L+tF{!4^BfnmzOq@I0Ajm<^Xv;735J%F!jG z(dr3R5`sm4jB-Cg@-C9LCPtAkz_b9Z-HZCB`$(Au&QEbzR!zO1 zMjYT(4S5sC*QouHXrey^xnb~w)dCHUUu@g_7?Iz`$>-hNmi6Tg*jx_t&DceFOm`qz z6Xwj&T4;Mgt1t$)42ys#J<1ZL2>H+Ut*ymZHJot8(U6s-sl1(F32&H#71st-69%JB z?S!7sr&CGYPUW&m_nteSET4r1Y|a4qHOXo`q8x0~Q#L;-%!}AwfL^f&r1+ImwlpvM zqkus;L%^9M+|kp3AOh1T0Y5;$*a0J=Q(Kuq1gS($lB1^q@{p6w1Q9}30WsOfcz_iG z?%(cg{dTb{nKt!oA>R{+3Yv!UxlO}@gtrEYS^EJqlRL(WJ}@<4nn}2CP&JF24zA*8 zkh^oo))ZG)>Cwu??x7r8b9p*I2#x903VC>c!0=d80ofH>5l}-Q66gKf{Uy=j1uENc zFk-NvagfDhgeTED0x%!a`4--Np=Tf*G;J+Jw65ghafpECbwQNYe&%y}&VC9d`ICt_Dz7zXBlg z^8kw(nCw7UJS6~#>;ReQ@(iXX1h|h!H89rTA3k7J5%6%;>P8%Oxbi$GTOcLTK|Hz_ zErs95Yhq0mTUSqx`IG1C9g!LHmOszJUv9FtrP?Y!p2aaR%xJ;cS(T0MLAcxME6F|z z;i=B?(}1l@5(MZ@qs@*uQU&13u$OiRDue&V!KO#uv%Oj{%L9;w&BZ(1PkPUV_F!D> zMY7K|wrXX10^7%d6dS6r4k8Y52m-Ht1xf)vYW|xdU{v-}c^<`gJP0qjHpa0J7XT5} zz+h@3tEaW&Dfq#=_zxow6CHg6$y-P;B0j#n5UQULI%MB&>2?#M*`LKOWzKplWV2zXj}pdhUXs(@o4 z4L~Z!T2a2yhec(wMJz^qT*NScKPZED+fL9F@1h|zCyb;XiHd~P6b)NjknBVv0P#d4 zm9%~LJdDgokVKFmlJmXQfUP+s=owEO9Lwd>zJunGyMP311-**o=SY45#H+7-OM$N) z>FW0s=BKSF!m3+``*8pI_?}oW))QT)s%omLjvu>b~lnf*X_^uvN1eS z_$p8v^8$WY(Um9R_6@At`x`t45yUw@Na%H(SMwEfPCu~xx`p+dP9ym~lJ}8}yJrUO zU5D`6Ysdp`(kCDw`;Wn^6Vw(eqsTYiPY1Mdik|>{!e*vf5u~7g3 delta 4853 zcmb6dTaX-8wQqM%PwzZ>XJ%)g+1*SYBs-h1n@uo;mBfH45enA4V8dt}d*}8hGdnMC z_n2gy%>W4`ios2884yG#79jY*$6~}ns-*DCKYy&UiGC=3y%i^FbQ3hTvb&8t#{9=QkA^q0zIx)LJSZ zl9F8)-~09CI|NorDsJ~ZmAsQZe4JS(-B&tM%$H1RF*h_@Vg=Jl&zy2B+YL5nPPSlW zE=Kzoe@8YDZ4flDLH>cfhZua1vc_is0?6@2rpR(If#h`v3|{x;*SF^{61O9r&g4zo zPN$jBGK6d!d01N{N&dRlOGfzbwZZN&M0?BNNN|nvfdBFBn{a+309VVH#f+6_Hy~yW zVpOY;b=b`~UnaZw8~@kkh~Vl&(k%$q@ls$XN$}?b`@;Q*=mn6}*%<$KV4`myVm=MP zCDw9Pd~dLz-HXJD#l_&uaxjHsZzG%;ch}Q6KZ?LakO452)Yx6{b@g)IbkLu!W}mVh ztKj(8!*^cF$u;?kJg+!fjnovXQ1yZWbU#r1IX&0W2*4xu-JdW?n;MZ@zNHRjRQ&IMxcgm0wzjeFllH|<0vHH}7YmgcpZR`bvK z*fmfZZ7c0TrD97)BTQq+KP^%1kn{lZb)ojBB^pQV@a;Y?)pPNurDwFJ0$7UWfw2eY zo}gz4dl<02OIVoo0VN8ua#J=sEgb@x;$Bs9dKbv4YebsYiB#PLeBetkr{C$T>1PPa zc!u3C(YiLTpVrYrDn{F+ZNlE1^%$m)fd`Aa?BuNE}l|tGPNzDG#R0eZf>kr2={JP+0M*z?|Mvznk zpQQI#Vi?^Oj>#H{QZoG>!3^E}PDA2z$Iz%Q6h!M7O(COt;vV zRQwE=RRKsuBh|^uh<3~Yjb=18oM=L%9we3&)A1*`aio8o1*PaF$b1}T^a2~ zAjOmz`=TV(!DFt^n=WNZv4`mLl?BHyR@lE2?f*#T3nkT_LypOuZ1GqE%&9kv%-Gmi zb^WxN6?n*qNE4()^8m7?BJeOg!R#wRNqUFEh+$@^M)$RNu_l!&&bmqn@Lue^ef5#+ zPh71IwRvW<#jJhYqLV^%U7YRis=hTLtlM1;ZB2MpByZ8()tNnlZgseLeG}JJo}TkUw&>fk?ePMNcLrjqCJ-DFU(P#v8}kHr7W%H zO4%ZVt$M}HD{66=y8cY5ShO;Z+s(K2b=TQa4eLkl3WAde;DDi4lv%duxIP=*&ahaf zw1S9s3Hk=9;%#-ORmQ5q0 zNcAF~hWKMW{RgH1DaopAkcbjdVx))kC>mS>O%ACcH3C?j1mLFpf`3EePLSI6lbuS2#QLs352uey zDbTcd>Hj%g0#8wx#Gb{`^8j3p6@(4nMa&BTT8pDcQjyjH!G(6LqGPick?(s5zK>u~ z1aI3#>|21mZE?@~U8F9e=Lg6n3eeKx!j`rL>?LGrFYn#vl8Y^*S8-rfq6syof_8>w%Z{kR5Kfzcaph6ET^Ngy^U`LyoX=)V2WrSHk8b+x z%;!KsP0C5^h(mI6L&5PC!j4oU4s?><3>%>0c4%g_Q?TuMXo#uLV(^o2luXpyJNWyfi4B!bKs1|$ zm%e)a{KC7xe29GsnT{e@0Ki|_!pLoW%hn_5nAa2ZAxV_FBRCSz;YA#sMIee!`>KhT zB^yA(QwXjg5HW~_g<&9y`>yY~-U*Vn&+7)(|oWxE}sOG+2)W2uX_&P`Pe&^WQ zZoW diff --git a/app/tools/__pycache__/check_update.cpython-39.pyc b/app/tools/__pycache__/check_update.cpython-39.pyc index 8f378d91e9a6afc3c475c799e83bea8320bf4a0c..65d4b7a54141e8a2bbaec035b871f030e6c867a0 100644 GIT binary patch delta 223 zcmew?^jU}}k(ZZ?0SMj|YGrQZxyj6UYw7UZM?HQREU0RZH`H3t9y delta 223 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 G3PFRRRuDmmQ5plrhke;h_e|-Q?QT6Yt4Oxl zm@NSlLuif=BQ#Kh0dJtupot>B_`<6`=y@NYT#P>aS(BLmD#}ozxhu>sg19qguxN z4K)WdhNK4y`AE_i3SlJ8mn!4MAdjr2j|H2j;R`PS1X`9bEvqw@Tz6koZ;K@HsUSgk(e~-H^oKB^j0^_(0=n@eCa# zo|vLXh%IL6sV&Qa&3h150AyohK0hAtT(M9JcpAwHy2Lqi6-kSa&D|ZSA>H9ZG02Vk z(FnK2pxZ0@`#MC`?QvI5=vDoSS=B_b?@2<$^}arF%UWM^(H6FAu!0t6?@Tv7d1vmz z>DjMuHLiX(|Hb?L>v$X(2Q!Y;%b|3}{Nn*D@K93pB5hcg{IP&1K}edf@j?{v6s&m% zK!$Ra$Z8~XB0Pl9PN267_Rwl&6Y`|^&gpuh9g4v>qs)V%P(j3sWuN8p<hl8TCR6_2WrZ-+jPAidFY>SM8InBtpJ$YaFAn_vGM!LvJD0PCm>ao zW;gulT_KFjkO?i)nO@Z{YSVh15G^uBDYkruggb#_v^iA` zCXiI7#X!*Qlcsz>ND*nLm0= zd=yXB5+Il-01FQu9Smzfe4z%MNQaAF?nW+HFzY(Mt8Bq)!f5H%j74Rutz3G!b?@xW#(VWYzInIt>Gb@~^Ru__+)Bc3Cp`m^hacP9Fhf9V5 zJxVV)5#%e8KU54P9W571&5^-Dk@komqN2Fg(Ob({StqOvsVhs`poOy|z4ok0cgPQ$ zS6VifuW%leA|>MvSBk~vRd@fW@g3mhdH6y+Uz!t#>4MkjCLa7#Mw;~C9_Eb_JEc<{ zMo;|Qxz-!Z5RSu^Sth=Js!xzT=~_2z`6>WOhsxz5--LS|;bDaB2s;tb=aP|E5#ijc z^MhAdxCX!>RM$zT3wN8XlXMK$Ui0t4TFGWw7mB((Y%3h8M1`VwWN**F?geuX@*|yr Uu`;U^gFSdsLcE$Bf^S;kf6oWidjJ3c diff --git a/app/tools/__pycache__/code_task_config.cpython-39.pyc b/app/tools/__pycache__/code_task_config.cpython-39.pyc index 6aba3321b6fcac0a746c15e0978f7fd67441fcc9..905248472626905e8647cce25785673bf3c63c40 100644 GIT binary patch delta 21 bcmZ4QwBCs)k(ZZ?0SMj|YGrQZQC0*1KJNu* delta 21 bcmZ4QwBCs)k(ZZ?0SLNF?`Le}QC0*1Kr98k diff --git a/app/tools/__pycache__/finance_manager.cpython-39.pyc b/app/tools/__pycache__/finance_manager.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfb545a1158d027e5c2cf4346caffcff587eac5a GIT binary patch literal 20849 zcmb_^dz2ehnxCpvdaKpycDoI>fyQ8C0XE=a7#2Jp45kMdXuR0NL&vOEbje0?cdNTf z!gfdPz}Ozl!`K7EW3XYmS=hm|J2o6R1B1;ldHj`=$DAZ5Ia|reW5;USCpkNt&1RGM z9J2ZSzFQ?#spVyIPNY*;_ujg7tL}Hd_xF{GJw3?~K7TQFZTU~8LZRQV;r|$D+=0XX zDGD=`51E>&k7;>Le)YUAzu|mXevP~#zma?dzu~dycr+i?c#Sa@8;|GXQjd%!#*_Kv zcq*S7Pv_I)J^7yTOgI+}R`FKl{}Z(pS{ui-uum$U!4D=r_X-;PVzi%85+rHPTVZkO11KM33X$0vG!yx;u!ar z?V4k3Dv#Ej_=A(Ra&@9O=0vvEC&x-oZ0?#v9w?>~V+NF_P%!wBY6UFgTq2MG7h4HFcA7edTC`{FhWA2$)pz<8U?mix}7U9-XT)2Jowrvj-N4MQm z9WQO$R2{AJzV^0z;RM%=-n+ff7{l_?pe$fY5-jFuw!`g>G8Vn&W7%%~aLAIZl`aWj5Q z6TCC>iBb}6;N3CZOq)IXjeS}^rEtwj`CwkZ9CvOWdiBhwKUGjacjANQ=dUWHAr8L% z!pK<+k&hEPo^awd?pUF0ItKB^i5ADJb?izM{btE>A`{hG$#&B2wiPCUP)^$2JJss( zHc&O=qnKw$)!H*E)a~Ak^)QaRaM+V58ro#07OH8p`dnzA)(92C4SjM&&6thMg=V9s zHpjkLBaAZMFi<8M5tPYB6lJOrLz!;GQT8+vC^PPry>lV7vVm5g83K0dBh&GfkF8lb zzGkJF>vzI-&2o%-9V?HpyxGyqrlsS_obW_-mlMbN?Ia^>Df+BsEJy*?Wh@A1>k1Y_ zEUrZ1B+7Pmd(|2*)|}+1RRR>u0_*ijLYDPh(lPAP*mmnuUi3T8+eTz-fVTmOlqbry zLV=HD526Se{n~&Q4SX}&^nedB)_NBm*PN(Ts@1KDQ4+TIVV$%p+p`XpMySFAn^4hl zU>hpfgbKExf(@tu{1pJd0?=2Irgkhv0N2;z!gHVh>HML0&V2e=^JlL&4}3a5d%Ai0 z@NZ8aJp04<&wTdMeOn$JX?}LNdGPh-i?99m^mE5k)=FITJHsN!!Pm050mX66x{mc0 zsVfM@YSn@XR>yPpB`88+MYbK~|CnCn2a$W#aa~BEXmK^8L0@_mzS`1F@&}VI;#co zT-XWkDAj@;qhq%9H4Jki;1?5i=T0QHTh(#di`y~C9zqcc>slP&qNVo2Z< zLF*12_FfbLiLlt^|BwWxaV%^CQ^573rI@LkF>v{~nb>dS4CjrSI z&^#V?l0`L+QX%ctDSVxjS+Ym1vM3OvRL{H*>m&~$jr&mP#@@l04Poe!9c0o`DPy(x zYyvDlDU3T6Xkj5+K;$F29@$9iDoku$&4NtBG5Ac@w^&UJ`YFZ32K!Yas9dszqg$(Z z&1x2HbT$<4_$GTdu;4^K6p-B~&TPS96T?DUe~ZV0zh+%n!cT&FRSja%gOj=N) z2m$vD&4PK%Xim!1^)Egkw+K-_IO$a=lsNTx z{|sPS2^|dW3|mG+`++`%2?Yo_O;86sUSE5oqtzfmWKAu4carPJpev77$0s+KnDoEn z2u-i`Kw_1~t522uuv@!+tU6j8vp1mPUAT1^x^Q@`G$FgxiGs2_VYNHFc|KjW$~&NW zjum)`JPJuj3A6r%w=CkMO=%s{liHw`!Pn5HmtOoC7f7)d60X1`M8Zv>#|LL1Qy}oQ zow^lm=;U)-LQ~MhK!SRmEb!b*pEM7@wotts0cH>#1++Qe%B*|YD+_7^xEDgi55Nk> zh;q%<@Y_bfj*-?H3=M2Q)fVdIcX1BVD%V0x!y#%5EyDfmF%<481;z{?ivh!oIz>i@ z!V;L@L$58IpA13JD^2v84b6puh()1deVava#nyMwx10U)%OTWVzA^F1DTD z=WS#=S9;KFsVdzzv}5aX5$k5o&}COaKVRpmuc2^aMJ0(lH<;SW3=UVjrA7tH`7#>G zXqQM`G^xG?kCqE7l}YJM*}q$F5`{^@VwewOJOLZo8bQ_C%;NW02-4ri+C?=es(!pc zu#p+2z4fCOi{Fma0cw= z2rT6Uw4bDzLOX#rd(zOcl)jWK!E%Piq`MkZT68Mt*>Y9Cxd>Nf&G*g(Z>MP|s53=7dZ^djY+`IlBp6oXBcJy53&2Fy8o_y2XfWE7- zR>JCA<{fCQba!~8c_&({+!^k|44cfm(Q}R4GmM^ZoA;n+we%3e_X39ZncqQQ&Nu3Q z^8xf+i=F}cWn>>l%m>kTo!5uoL31;%{(bWy^j|MJ^dnAYSh`Hgbg`F(nD z^flkz4;P>E>bY9>D~HZ}evBSF<;)Ww;0O%z1pEWVf>o{70$iAS4G-bMPomP$tSnR~ zP245g#0m1c#%2timdt@IJGl+T< z^*GHBGj>Ra87`I8r5r!QPza>)I(DjTgG_HC^e&$bqIo9pyc9?SXJ zU%3gAEBE&e&MN>#`o;R2k*!@p^NvS;5;_c@9X8)-4MTN6z2L$EmXX0Eeiq zp{Svy!*Lju89fd|BOa!});0bAOfLyyUCZKFs1b3EEu^^>4Qwy;A)pG7g&VvhWQO0- zsKK~8A2lX@nHpmp(zMXja^=kxo$u`2i8EikrFQJ>saNLT-rqd&;{2;0Z-ojC7cLiO zJMq$PsJ?~jPS_=nypO=NEh*-zdmE+Z}U7=FzJpqQ*vZwF<8DJnc^9@wYE1bn4u zK0VZY@j&y)pSS=%`N#A74!~P_p$FcoA{p!2ij9y>w5yfSG7ubX*M&&Ewtda55Hj)7 z#AwwlPwW^zPpbyxn|3LpXpff5pwtNy#5|Hqs=cF!#p+A|wf_#GUBPXU)&eS8wn zBCc2gJ54&L^{j>MWki|c-lIF(_6`bm1`Bo(R<(!a-pDU7jdF0qEfM$oa4$p?S#5e{ zCnj{AWr0j>?LT>qhwrlUz<^n84&0bhutt3F_Ic?{xE7v;_i9diB&0)1di%R2g#EoI zu)ma`(K`KxaNC^w{PT|ewI*<8#L+Bk5*3Sf8q5LGixU+-YFoQ_f)=A=Q0fFoXqx95 zEP_TKfT$#t>$~%S_-hQcsZWz%Q2Xu%xUN@voMRJjCY0po905xD0}N4+qzhqA7d?cu zWB`f=IizWTT2_Ht!k{OeK^{r@Tk)!}VC-@iW80kRYQUZtYk;#wYLVG!BhnRjw+0}saF@;= zg}VzOZG8_XM=UzD+d$666kz{8d)t70noSad7>5Dqia6TGQ-aI1b}xd^opAln80vbz zvMxfyXS9G92ugQetL)xzTPs|M*8z#R3iqPMP04Ubuo@bG2C1m8=T1OA(sL_vQ5R>D ziondj_JJaL>oH6K@}-e0Du6=08PzKcv+a5o))^#ftALUJ1&51BX()$S>}4H{FQ|eB z7#?{&5$Y~Zl14!lM)^EIRGI|nm0wRiF(l{X7$xor)a4O{9D)z#q z?RYfbuz*K~I(_T8GH58Du!;uDll7xhJ(-sp!GHy#PzL?1O3#cwRUE6s$xmV0i9T7m zwNGFF8w~Ouvr}v892H9G95vT>GF%#a4JQn)CS-UZGBWi#{M1}MZ z&cX}s3X;RmHxK;WZ&(g*t`3<7CMbWPM|5c+MH+c zhwIC5(ZWbm^PtPghPPs~+CUj5DE4#h{xI4m_I6pe#oQ_WWD>1J&>OEsXHjp&39nkbfrusGi@-hRNi?X>8$Nwr$;`7yKW!fP z=qwVoB!>&$j&oo9uzB=t_9H6)$;sv~_m6C~w&Uq?DJ4CL=N3h%6A`{9_LIWD=cRYF zI=N?^ifN~;(pa%pW-O{IMl&8Ze4P)yK;tBM zNP@DflnxEujw=SNTo~8~y?!N5D6ygTL4lw9AbtxM@YZ)R%x{ESa?j2sQ!My(2(@}b z=j&W@6qAHNvxvTRF7o162I!VE5L;zU+@`K{8v@-5waysR8BeRD;Fwqk!4lc?hY&0g z2$rQa*r<(2K(K^oB6}kfNmG6)RvKa8GPppC1uD7W*Yt+#LwJ;h{mOCKY{{0mk0Xd; zO*FM$VDTc0Lo7y6EL8o3OK`!~ODsA7-|xx^AM9@@z`5%#`v@cVLS)R<;prft?GzD=Kr&BVzjkgan| z4Nd^m<23uHZlTJJaDEK3CxQ&N5Lku=6`TyWQ~CrzpNs#l$xvHC@@ud1n^FMy?+{t(Rm<~VJ z{0~pgzxYh^-8bjonv?YAqvxM~4t}nY1*QV_LIrQhFbM|i?;WVZb4(%!Z`zG5Lsp`E8spfeCP5GuB84)Tzi!dT*L*Fr_ATI^TVW*RRHMnRyQak%w|9j$P|SUX*w6i?-dYrOle^c1XIM!Dj}t47JE zWEqjeiQ#(jtH<)?$zeL!)A@Th7dG8JeE-I+cW+XmM`KrUY^U`q$47Qq&<)yZ8B!|S z+=#Nps-QqJsoGwd+TcALgMn%0%_0H^9bgP^0~m5T!BXY?$BNddBx80{<_6t4J@@`3 zVuJ_@zD=~G7^mZaj%i&R(wWH42xwAUtGh0QPS0NV*>buQ$K(3&k}SgeP?EOr@+I8( zh&H`hh0-OLOPv0|0PL%Ha1bk<(+^+IkkBksoXEt8k*q;(n#QG2xH&$6PmlWXiEk@Z zV$chpuElE!rniCtLYL&#bRJexW<>Q9zks<>-<_ArozsmdCF_Fw{3>vtCCQMJ^08Vcf7(`+56s0u1bAV5ZP)FP+3RX-TU`G;3WgJKNVlraH{t z>})?wU(gxK#6CFrA>Tu@i6{bR}j zzK5rFvUr}w3n(0e$)naEu-&qcJhk8-v-dQLeAWxyKw?bP5R3ii$TWIp9~i$L(+6|g0?Ph7S>XYorG zU$FQUi+{l4AF}8sEf%>m`ZI0*12J|8SA-xW=vm5WSqKeJSY$<52zGXAGF>JMpeD^N z9(Uoe{{jV(gUpZ2t)hD6<&WSry#&1%iA! zd@E%?umqqR5TLuoX}yaR)_W|1y0`Tc^ew@YC{uIY|I1UjmZtSSrpWaRl{=Bqu~N}e zq%2P17!^3O{$KOv&#)k9RB(~}ykl3a1MIt#1+7r)Pg$%)0Y}Aktp76>B0WUF(6Y!U z#bO}=+u}C1HgQnLN-4qq8UV7_p(1Jf@cJ4|(x7Qc%K~)D_YqY}GNP8@evv1JmI)8& z(?eec8_(K^kJ?Z9R5~&#??WeEOQrjlXei2+KwQfkG`*jq1v!$4g(HRww}j+58iyZ- zDrO)$PIZTo0KAc8#@|5@4|E@{L_uY%Kvn2RJb*C)IQfv}6RRX~;N{awdWWcHQzH-w z;eZnOe22gQ+lNunv*({eTp-+o;2*_BJfIeZXX1OslMOE|Y9cP^BuuH`pU*T<*$yx* z?%MLOdbM&`rAI2IhXgvEkd&V_c6kSgC^k{rHCCR0PXecqmO}r@{Oj+{AN#RX&p-Qv z^Y6S>Coq+7=FDfG$%*E{@8gYaRekr_`H$Y0NU`xJJnG4vY;<=whq#-K@pD z7k69UhqK)f712v16@VuW^Vf?Z`{I{jH+~5V1Ri9tZfem;#_Pv~{;-|eH$?0FAxz=c z!UM4M?jcNn7*BRV034)yybOr<#=O_NZy^|Ydk>6^=TVVFG-O!^xct|-L0>0c9W&)+ zeL=JDWw2qHm4?@_w3gZh*W8$d!>C zw)4*(YX0E!=8;2+Ke+g1{R?c0qylwh0*xpt5EIPim>P;Y$y`O+{j+#1V{2}p%`-%Z zA&`M=#NEn%`d6GrWZp*B#75i2+HMw4vk+se#VxvqJ!UWtZwiax`zEjXcP#!r3!=Ic zE}OfRFdSpwJ{DvxPS)?kWA0^FwY3+S(EQ^Hk2>xmb&w&ose=)317WKq%`AFjB~+@z ztXeHmk*szL>Z?@jzcbd*F@1o;Pz<(+WOI;6TB6Y9FtqCL_wyKRx*`RT6aD=VeSb+m zg^n57gC_OBq?l|ei^76^^rnMNC67yOnd<;ycQsZc$*ZgzcEQriV&he zd5CBs1k46PfZzoo;O%GEgV81gCf5E}|EwT`4K5j64>Cx&WPtyN=pci{-o(@fkO6*$ z3^w@4AncNX;k<}Yx~G$P$KFU-#ij`sv$ub;7$5n)YL>$S`zw|Af z;&3VG4k8f#aE4nz#TBH0!bDxqS|tKyn4T7R?j)fl0{?on5}ykn(GI^fgI70aV(@Cm z8;B(y(H_4Men1tqPQb*3U)`=vZKHR64kD%u4>{t1DeKo5lSWtvb&Tq1^q{AQ_q2X( zB4OresL@mD0sVz%GTOIl8G|qe^?w7(G3LmEJFRNXm{l`MpUlY` zxy4t`nhea^hwB=xS^HYEHq?{yEM7wW>RHpiSs`4_9<*b#{qP<^C!5-4!rxkf0Idwv z7S9estS*6Ajnyt`#PF(BFJ2w!tzBAK+UNy8!+$lv4Uh#ymYMwxtW&(ai(1Nq67pw) z+|BhpEkB~~Sq=WyC&t8O=0Kw_z~2_l^zH2<7MM~KV`32qVR0S*a^>pluC9+4uhx!R z{12p|GoQYKe`sm_TMJ?dLn_+?;n>!jSgnd0ckblJ^KZQL+tY8h`tko(@^0JwbH|$> zz6zxQC*3ZA^KYCS>VAhcL+T|X|D;2Bo6d8IN`^PzkdXhB^1U`l0h&*VZhnboe>qfiLpYhTr2MqT8=a`=Z7O{KQ$ zBgpv0ALHPYTl2fT-n|XWQO;k{F2>osodxw}^@{g1tVtICe%1tW3aovf1x1wg9E&Y1 z4zoDIVweR5mh}b;BAE3iiyyPt%;HuSCs=&M;vcd2CoKLs3yG8b8EX!U|HR_YS^S2@ ze`B#ISPZba6$Moln-#jH1}@DcveEu%wr?QOA0JE(#0HFhBb&Lrw?7H6|806;FxsE( zUpyFt(~sXTxs~{SnO-^2-@ka^y3Anan*L?|JpG)R)Ux&MeGW=GM%H{|i2bk@Wxo literal 0 HcmV?d00001 diff --git a/app/tools/__pycache__/part_download.cpython-39.pyc b/app/tools/__pycache__/part_download.cpython-39.pyc index dc02841eba8a93174848745e07236bfbe9782e37..81d155ee829d952e453051b7bf4da03c3b5ea70a 100644 GIT binary patch delta 21 bcmZ3-yN;J9k(ZZ?0SMj|YGrQZS;PhaH_QcJ delta 21 bcmZ3-yN;J9k(ZZ?0SLNF?`Le}S;PhaISB={ diff --git a/app/tools/__pycache__/update_check_thread.cpython-39.pyc b/app/tools/__pycache__/update_check_thread.cpython-39.pyc index a77f0014cf191004f2d0c3612be33267cb395459..b46ec3c5b5e8ff2676483496b10a52f7f7ce10ec 100644 GIT binary patch delta 21 bcmcb^d54oHk(ZZ?0SMj|YGrQZxxfMdKE4It delta 21 bcmcb^d54oHk(ZZ?0SMmozscChbAbf_L Date: Thu, 1 Jan 2026 16:58:36 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0fdcan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 22 -- app/code_page/bsp_interface.py | 95 +++++ app/tools/analyzing_ioc.py | 27 +- assets/User_code/.DS_Store | Bin 10244 -> 8196 bytes assets/User_code/bsp/describe.csv | 1 + assets/User_code/bsp/fdcan.c | 576 ++++++++++++++++++++++++++++++ assets/User_code/bsp/fdcan.h | 137 +++++++ assets/User_code/config.csv | 2 +- 8 files changed, 835 insertions(+), 25 deletions(-) delete mode 100644 .vscode/settings.json create mode 100644 assets/User_code/bsp/fdcan.c create mode 100644 assets/User_code/bsp/fdcan.h diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e5eccc8..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "files.associations": { - "user_math.h": "c", - "bsp.h": "c", - "stdint.h": "c", - "array": "c", - "string": "c", - "string_view": "c", - "vector": "c", - "can.h": "c", - "device.h": "c", - "gpio.h": "c", - "uart.h": "c", - "motor_rm.h": "c", - "mm.h": "c", - "capacity.h": "c", - "error_detect.h": "c", - "bmi088.h": "c", - "time.h": "c", - "motor.h": "c" - } -} \ No newline at end of file diff --git a/app/code_page/bsp_interface.py b/app/code_page/bsp_interface.py index efbc26c..5cd1c03 100644 --- a/app/code_page/bsp_interface.py +++ b/app/code_page/bsp_interface.py @@ -318,6 +318,14 @@ def get_available_can(project_path): return analyzing_ioc.get_enabled_can_from_ioc(ioc_path) return [] +def get_available_fdcan(project_path): + """获取可用的FDCAN列表""" + ioc_files = [f for f in os.listdir(project_path) if f.endswith('.ioc')] + if ioc_files: + ioc_path = os.path.join(project_path, ioc_files[0]) + return analyzing_ioc.get_enabled_fdcan_from_ioc(ioc_path) + return [] + def get_available_spi(project_path): ioc_files = [f for f in os.listdir(project_path) if f.endswith('.ioc')] if ioc_files: @@ -618,6 +626,92 @@ class bsp_spi(BspPeripheralBase): ) +class bsp_fdcan(BspPeripheralBase): + def __init__(self, project_path): + super().__init__( + project_path, + "FDCAN", + {'header': 'fdcan.h', 'source': 'fdcan.c'}, + "BSP_FDCAN", + "hfdcan", + "fdcan", + get_available_fdcan + ) + + def _generate_header_file(self, configs, template_dir): + """生成FDCAN头文件,包含动态宏定义""" + template_path = os.path.join(template_dir, self.template_names['header']) + template_content = CodeGenerator.load_template(template_path) + if not template_content: + return False + + # 生成枚举 + enum_lines = [f" {self.enum_prefix}_{name}," for name, _ in configs] + content = CodeGenerator.replace_auto_generated( + template_content, f"AUTO GENERATED {self.enum_prefix}_NAME", "\n".join(enum_lines) + ) + + # 生成FDCAN实例使能宏定义 + macro_lines = [] + for name, instance in configs: + fdcan_num = ''.join(filter(str.isdigit, instance)) # 提取数字,如FDCAN1 -> 1 + macro_lines.append(f"#define {instance}_EN") + + # 替换宏定义区域 + content = CodeGenerator.replace_auto_generated( + content, "AUTO GENERATED FDCAN_EN", "\n".join(macro_lines) + ) + + # 生成FIFO配置宏定义 + fifo_lines = [] + fdcan_count = len(configs) + for idx, (name, instance) in enumerate(configs): + fdcan_num = ''.join(filter(str.isdigit, instance)) + # FDCAN1使用FIFO0,其他使用FIFO1 + if instance == 'FDCAN1': + fifo_lines.append(f"#define {instance}_RX_FIFO 0") + else: + fifo_lines.append(f"#define {instance}_RX_FIFO 1") + + content = CodeGenerator.replace_auto_generated( + content, "AUTO GENERATED FDCAN_RX_FIFO", "\n".join(fifo_lines) + ) + + output_path = os.path.join(self.project_path, f"User/bsp/{self.template_names['header']}") + CodeGenerator.save_with_preserve(output_path, content) + return True + + def _generate_source_file(self, configs, template_dir): + """生成FDCAN源文件""" + template_path = os.path.join(template_dir, self.template_names['source']) + template_content = CodeGenerator.load_template(template_path) + if not template_content: + return False + + # Get函数 + get_lines = [] + for idx, (name, instance) in enumerate(configs): + get_lines.append(f" case {idx}: return {self.enum_prefix}_{name};") + content = CodeGenerator.replace_auto_generated( + template_content, "AUTO GENERATED FDCAN_GET", "\n".join(get_lines) + ) + + # Handle函数 + handle_lines = [] + for name, instance in configs: + fdcan_num = ''.join(filter(str.isdigit, instance)) + handle_lines.append(f"#ifdef {instance}_EN") + handle_lines.append(f" case {self.enum_prefix}_{name}: return &{self.handle_prefix}{fdcan_num};") + handle_lines.append(f"#endif") + content = CodeGenerator.replace_auto_generated( + content, f"AUTO GENERATED {self.enum_prefix}_GET_HANDLE", "\n".join(handle_lines) + ) + + output_path = os.path.join(self.project_path, f"User/bsp/{self.template_names['source']}") + CodeGenerator.save_with_preserve(output_path, content) + return True + + def patch_uart_interrupts(project_path, uart_instances): """自动修改 stm32f4xx_it.c,插入 UART BSP 相关代码""" it_path = os.path.join(project_path, "Core/Src/stm32f4xx_it.c") @@ -1166,6 +1260,7 @@ def get_bsp_page(peripheral_name, project_path): special_classes = { "i2c": bsp_i2c, "can": bsp_can, + "fdcan": bsp_fdcan, "spi": bsp_spi, "uart": bsp_uart, "gpio": bsp_gpio, diff --git a/app/tools/analyzing_ioc.py b/app/tools/analyzing_ioc.py index 6a85c3d..542cbb4 100644 --- a/app/tools/analyzing_ioc.py +++ b/app/tools/analyzing_ioc.py @@ -71,7 +71,7 @@ class analyzing_ioc: @staticmethod def get_enabled_can_from_ioc(ioc_path): """ - 获取已启用的CAN列表 + 获取已启用的CAN列表(不包括FDCAN) 返回格式: ['CAN1', 'CAN2'] 等 """ enabled_can = [] @@ -84,12 +84,35 @@ class analyzing_ioc: key, value = line.split('=', 1) key = key.strip() value = value.strip() - if key.startswith('Mcu.IP') and value.startswith('CAN'): + # 只匹配CAN,不包括FDCAN + if key.startswith('Mcu.IP') and value.startswith('CAN') and not value.startswith('FDCAN'): can_name = value.split('.')[0] if '.' in value else value if can_name not in enabled_can: enabled_can.append(can_name) return sorted(enabled_can) + @staticmethod + def get_enabled_fdcan_from_ioc(ioc_path): + """ + 获取已启用的FDCAN列表 + 返回格式: ['FDCAN1', 'FDCAN2', 'FDCAN3'] 等 + """ + enabled_fdcan = [] + with open(ioc_path, encoding='utf-8', errors='ignore') as f: + for line in f: + line = line.strip() + if not line or line.startswith('#'): + continue + if '=' in line: + key, value = line.split('=', 1) + key = key.strip() + value = value.strip() + if key.startswith('Mcu.IP') and value.startswith('FDCAN'): + fdcan_name = value.split('.')[0] if '.' in value else value + if fdcan_name not in enabled_fdcan: + enabled_fdcan.append(fdcan_name) + return sorted(enabled_fdcan) + @staticmethod def get_enabled_uart_from_ioc(ioc_path): """ diff --git a/assets/User_code/.DS_Store b/assets/User_code/.DS_Store index e391af5deab85694ed97fedde8261f16f37636ad..0f8f41bc99c66a52bca62641c16b21284e74bcf7 100644 GIT binary patch delta 171 zcmZn(XmOBWU|?W$DortDU;r^WfEYvza8E20o2Vx_*+7Lw9LQ(j1!6{^I75DNQcivn zNXf>FX6zFmjxnwxn9?l4Uj6V{o`BVxPpiUp$}Gsp~} x(cD176=eLzi{F_i^Q-7GGE6q%QRV;|4YHbHay-w}$qQvCPZkoohA_aC5dbC5B+&o> literal 10244 zcmeHMO>7%Q6n^8Rjoq}V^VeUHtoj0KD2bD{i4fFv8$p2nU{@ufKdyf^&XV=6@vf6L zQ7ZR>RC+*g;eLFCT4|-r(CZhbjS#jD>9i+elfdv8!1QrM^5LjS? z7T~iNDeOD%?b_fOSRk;#|Jnk)Kg5ukCLLP0soXm7Unk%ewf)3zM`q7H8}W#2(`6u+T0QD2zQ1rWM+){jFq!$W-3=b$8Tp0L(4bHx%^pG zna@W1jv2a@Q+1^(8PuYJF6UoY^`bGKGHQC!l)M?cAsh)uve8|Oi-|*{1F>g@4=)YG z7RM5U1F?}qBTGw>aDV*S=hE3(t*jgG*lGx8E1+#YwQl%zQVVlV%s_nC(CMdWw4qgG zOXt>YUE8DGJ-yw1-TnPLcJAum-LviyJP02>Lo6vcpVCbi- z${ci^w3N$MMqNNtkB=d(6fdq;ow-s$pT5-!DfGpvqUh&JRke6(dfHU1NmqG_M=Mkf zO*?Ivs-+tG)Ok6&rIaW1X#*qj3{F+J$vmr6P0%Ku$*Ekmn$t^4>dFNzmshk?ddjdY zqdciX3!b?gGE>PFRJ{~G@`r8ENIdzJU5Zk?VdHpmrY_6jzDAWp#Tnhu6)>H)E8@vl zoR%={r=ygi^Yj+g=>z(hKBcee4*g7j(z4hlc8GmqzZeh)#bJ>Y6XIoYPFxZ>@utlm zYAp1Vjy#7569td+&Sk2)X6PltYFH_hK#z-dSZR4#N-C3q zFjS2+JA~!x%csps2nyvbbb`|8okzCl0K#4-nO^zg8%*K_m;8v2r$SeJ9MDf(Z3Mb7 zN`xw;Q%MHZ42;smK?_Y|q@nFmI*zf%!BM87cMSRka__ii)sFe+F#B0=zfjeu@k+m< zS+)=D=G;ncoXi zmI~Q=D|up{PhP)Ao`(4-;N&@SjM0R|(i)NwY4pr&ZAt6s7=pvBDam#-)=yvGTD%Y* zNjqHHm8G*<(1>+2XdV(Z&>Y@cSw00>&f-hUce!Ngu+6-jkJ^%#SIy1qwhh~~j8(^n zv%W@hz1Eh*?wJ3Fl6bw`l6qYFxK}7E{pfNlz2r){Ww`aSy^ytI-^;=iXP{w$W?M?) zm2ykkI<@EOR|}mdJKtSOe^meL#@*>I@HKssY!A=o(vhXi_t&p!saC!DllN>}o!5R% z-<-aye0JY4U@6ZSa{2Mtj@$-|SE%CM00eJFzqvLer`My#2SdY&f!NS!;vw;YqmA#t z*bGZxBgYzBP22fBpFKQ%AGK8yiLrs$@aVx+s|+7{Ak^g2e}kxrVbktCd-t?PO>Thk z7~rL55V(SxR$xyn^wbQR;AoHxPbTaIXm +#include +#include + +/* Private define ----------------------------------------------------------- */ +#define FDCAN_QUEUE_MUTEX_TIMEOUT 100 + +/* Private macro ------------------------------------------------------------ */ + +/* ===== FDCAN_FilterTypeDef 配置表 ===== + * 定义每个FDCAN实例的过滤器参数表。 + * 过滤器表参数说明: + * idx idtype ftype id1 id2 rxidx + * 过滤器编号 标识符类型 过滤器类型 过滤器ID1 过滤器ID2 接收缓冲区索引 + */ +#ifdef FDCAN1_EN + #define FDCAN1_FILTER_CONFIG_TABLE(X) \ + X(0, FDCAN_STANDARD_ID, FDCAN_FILTER_MASK, 0x000 , 0x000 , 0) \ + X(1, FDCAN_EXTENDED_ID, FDCAN_FILTER_MASK, 0x00000000, 0x00000000, 0) + #define FDCAN1_GLOBAL_FILTER FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE/* 全局过滤器参数(用于 HAL_FDCAN_ConfigGlobalFilter) */ +#endif +#ifdef FDCAN2_EN + #define FDCAN2_FILTER_CONFIG_TABLE(X) \ + X(0, FDCAN_STANDARD_ID, FDCAN_FILTER_MASK, 0x000 , 0x000 , 0) \ + X(1, FDCAN_EXTENDED_ID, FDCAN_FILTER_MASK, 0x00000000, 0x00000000, 0) + #define FDCAN2_GLOBAL_FILTER FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE/* 全局过滤器参数(用于 HAL_FDCAN_ConfigGlobalFilter) */ +#endif +#ifdef FDCAN3_EN + #define FDCAN3_FILTER_CONFIG_TABLE(X) \ + X(0, FDCAN_STANDARD_ID, FDCAN_FILTER_MASK, 0x000 , 0x000 , 0) \ + X(1, FDCAN_EXTENDED_ID, FDCAN_FILTER_MASK, 0x00000000, 0x00000000, 0) + #define FDCAN3_GLOBAL_FILTER FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE/* 全局过滤器参数(用于 HAL_FDCAN_ConfigGlobalFilter) */ +#endif + +/* ====宏展开实现==== */ +#define FDCAN_FILTER_TO_RXFIFO_ENUM_INNER(FIFOIndex) FDCAN_FILTER_TO_RXFIFO##FIFOIndex +#define FDCAN_FILTER_TO_RXFIFO_ENUM(FIFOIndex) FDCAN_FILTER_TO_RXFIFO_ENUM_INNER(FIFOIndex) +#define FDCAN_CONFIG_FILTER(idx, idtype, ftype, id1, id2, rxidx) \ + sFilterConfig.FilterIndex = (idx); \ + sFilterConfig.IdType = (idtype); \ + sFilterConfig.FilterType = (ftype); \ + sFilterConfig.FilterConfig = (FDCAN_FILTER_TO_RXFIFO_ENUM(FDCANX_RX_FIFO)); \ + sFilterConfig.FilterID1 = (id1); \ + sFilterConfig.FilterID2 = (id2); \ + sFilterConfig.RxBufferIndex = (rxidx); \ + HAL_FDCAN_ConfigFilter(&hfdcan, &sFilterConfig); + +#define FDCAN_NOTIFY_FLAG_RXFIFO_INNER(FIFO_IDX) FDCAN_IT_RX_FIFO##FIFO_IDX##_NEW_MESSAGE +#define FDCAN_NOTIFY_FLAG_RXFIFO(FIFO_IDX) FDCAN_NOTIFY_FLAG_RXFIFO_INNER(FIFO_IDX) +#define FDCANx_NOTIFY_FLAGS(FIFO_MACRO) (FDCAN_NOTIFY_FLAG_RXFIFO(FIFO_MACRO) | FDCAN_IT_TX_EVT_FIFO_NEW_DATA | FDCAN_IT_RAM_ACCESS_FAILURE) + +#define FDCANX_MSG_PENDING_CB_INNER(FIFO_IDX) HAL_FDCAN_RX_FIFO##FIFO_IDX##_MSG_PENDING_CB +#define FDCANX_MSG_PENDING_CB(FIFO_IDX) FDCANX_MSG_PENDING_CB_INNER(FIFO_IDX) +/* Private typedef ---------------------------------------------------------- */ +typedef struct BSP_FDCAN_QueueNode { + BSP_FDCAN_t fdcan; + uint32_t can_id; + osMessageQueueId_t queue; + uint8_t queue_size; + struct BSP_FDCAN_QueueNode *next; +} BSP_FDCAN_QueueNode_t; + +/* Private variables -------------------------------------------------------- */ +static BSP_FDCAN_QueueNode_t *queue_list = NULL; +static osMutexId_t queue_mutex = NULL; +static void (*FDCAN_Callback[BSP_FDCAN_NUM][HAL_FDCAN_CB_NUM])(void); +static bool inited = false; +static BSP_FDCAN_IdParser_t id_parser = NULL; +static BSP_FDCAN_TxQueue_t tx_queues[BSP_FDCAN_NUM]; +static const uint8_t fdcan_dlc2len[16] = {0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64}; + +/* Private function prototypes ---------------------------------------------- */ +static BSP_FDCAN_t FDCAN_Get(FDCAN_HandleTypeDef *hfdcan); +static osMessageQueueId_t BSP_FDCAN_FindQueue(BSP_FDCAN_t fdcan, uint32_t can_id); +static int8_t BSP_FDCAN_CreateIdQueue(BSP_FDCAN_t fdcan, uint32_t can_id, uint8_t queue_size); +static void BSP_FDCAN_RxFifo0Callback(void); +static void BSP_FDCAN_RxFifo1Callback(void); +static void BSP_FDCAN_TxCompleteCallback(void); +static BSP_FDCAN_FrameType_t BSP_FDCAN_GetFrameType(FDCAN_RxHeaderTypeDef *header); +static uint32_t BSP_FDCAN_DefaultIdParser(uint32_t original_id, BSP_FDCAN_FrameType_t frame_type); +static void BSP_FDCAN_TxQueueInit(BSP_FDCAN_t fdcan); +static bool BSP_FDCAN_TxQueuePush(BSP_FDCAN_t fdcan, BSP_FDCAN_TxMessage_t *msg); +static bool BSP_FDCAN_TxQueuePop(BSP_FDCAN_t fdcan, BSP_FDCAN_TxMessage_t *msg); +static bool BSP_FDCAN_TxQueueIsEmpty(BSP_FDCAN_t fdcan); + +/* Private functions -------------------------------------------------------- */ +static BSP_FDCAN_t FDCAN_Get(FDCAN_HandleTypeDef *hfdcan) { + if (hfdcan == NULL) return BSP_FDCAN_ERR; + if (hfdcan->Instance == FDCAN1) return BSP_FDCAN_1; + else if (hfdcan->Instance == FDCAN2) return BSP_FDCAN_2; + else if (hfdcan->Instance == FDCAN3) return BSP_FDCAN_3; + else return BSP_FDCAN_ERR; +} + +static osMessageQueueId_t BSP_FDCAN_FindQueue(BSP_FDCAN_t fdcan, uint32_t can_id) { + BSP_FDCAN_QueueNode_t *node = queue_list; + while (node != NULL) { + if (node->fdcan == fdcan && node->can_id == can_id) return node->queue; + node = node->next; + } + return NULL; +} + +static int8_t BSP_FDCAN_CreateIdQueue(BSP_FDCAN_t fdcan, uint32_t can_id, uint8_t queue_size) { + if (queue_size == 0) queue_size = BSP_FDCAN_DEFAULT_QUEUE_SIZE; + if (osMutexAcquire(queue_mutex, FDCAN_QUEUE_MUTEX_TIMEOUT) != osOK) return BSP_ERR_TIMEOUT; + BSP_FDCAN_QueueNode_t *node = queue_list; + while (node != NULL) { + if (node->fdcan == fdcan && node->can_id == can_id) { + osMutexRelease(queue_mutex); + return BSP_ERR; + } + node = node->next; + } + + BSP_FDCAN_QueueNode_t *new_node = (BSP_FDCAN_QueueNode_t *)BSP_Malloc(sizeof(BSP_FDCAN_QueueNode_t)); + if (new_node == NULL) { osMutexRelease(queue_mutex); return BSP_ERR_NULL; } + new_node->queue = osMessageQueueNew(queue_size, sizeof(BSP_FDCAN_Message_t), NULL); + if (new_node->queue == NULL) { BSP_Free(new_node); osMutexRelease(queue_mutex); return BSP_ERR; } + new_node->fdcan = fdcan; + new_node->can_id = can_id; + new_node->queue_size = queue_size; + new_node->next = queue_list; + queue_list = new_node; + osMutexRelease(queue_mutex); + return BSP_OK; +} + +static BSP_FDCAN_FrameType_t BSP_FDCAN_GetFrameType(FDCAN_RxHeaderTypeDef *header) { + if (header->RxFrameType == FDCAN_REMOTE_FRAME) { + return (header->IdType == FDCAN_EXTENDED_ID) ? BSP_FDCAN_FRAME_EXT_REMOTE : BSP_FDCAN_FRAME_STD_REMOTE; + } else { + return (header->IdType == FDCAN_EXTENDED_ID) ? BSP_FDCAN_FRAME_EXT_DATA : BSP_FDCAN_FRAME_STD_DATA; + } +} + +static uint32_t BSP_FDCAN_DefaultIdParser(uint32_t original_id, BSP_FDCAN_FrameType_t frame_type) { + (void)frame_type; + return original_id; +} + +static uint32_t BSP_FDCAN_EncodeDLC(uint8_t dlc) { + if (dlc <= 8) return dlc; + if (dlc <= 12) return FDCAN_DLC_BYTES_12; + if (dlc <= 16) return FDCAN_DLC_BYTES_16; + if (dlc <= 20) return FDCAN_DLC_BYTES_20; + if (dlc <= 24) return FDCAN_DLC_BYTES_24; + if (dlc <= 32) return FDCAN_DLC_BYTES_32; + if (dlc <= 48) return FDCAN_DLC_BYTES_48; + return FDCAN_DLC_BYTES_64; +} + +static void BSP_FDCAN_TxQueueInit(BSP_FDCAN_t fdcan) { + if (fdcan >= BSP_FDCAN_NUM) return; + tx_queues[fdcan].head = 0; + tx_queues[fdcan].tail = 0; +} + +static bool BSP_FDCAN_TxQueuePush(BSP_FDCAN_t fdcan, BSP_FDCAN_TxMessage_t *msg) { + if (fdcan >= BSP_FDCAN_NUM || msg == NULL) return false; + BSP_FDCAN_TxQueue_t *queue = &tx_queues[fdcan]; + uint32_t next_head = (queue->head + 1) % BSP_FDCAN_TX_QUEUE_SIZE; + if (next_head == queue->tail) return false; + queue->buffer[queue->head] = *msg; + queue->head = next_head; + return true; +} + +static bool BSP_FDCAN_TxQueuePop(BSP_FDCAN_t fdcan, BSP_FDCAN_TxMessage_t *msg) { + if (fdcan >= BSP_FDCAN_NUM || msg == NULL) return false; + BSP_FDCAN_TxQueue_t *queue = &tx_queues[fdcan]; + if (queue->head == queue->tail) return false; + *msg = queue->buffer[queue->tail]; + queue->tail = (queue->tail + 1) % BSP_FDCAN_TX_QUEUE_SIZE; + return true; +} + +static bool BSP_FDCAN_TxQueueIsEmpty(BSP_FDCAN_t fdcan) { + if (fdcan >= BSP_FDCAN_NUM) return true; + return tx_queues[fdcan].head == tx_queues[fdcan].tail; +} + +static void BSP_FDCAN_TxCompleteCallback(void) { + for (int i = 0; i < BSP_FDCAN_NUM; i++) { + BSP_FDCAN_t fdcan = (BSP_FDCAN_t)i; + FDCAN_HandleTypeDef *hfdcan = BSP_FDCAN_GetHandle(fdcan); + if (hfdcan == NULL) continue; + // 消费所有 TX EVENT FIFO 事件,防止堵塞 + FDCAN_TxEventFifoTypeDef tx_event; + while (HAL_FDCAN_GetTxEvent(hfdcan, &tx_event) == HAL_OK) { + // 可在此统计 MessageMarker、ID、时间戳等 + } + // 续写软件队列到硬件 FIFO + BSP_FDCAN_TxMessage_t msg; + while (!BSP_FDCAN_TxQueueIsEmpty(fdcan)) { + if (HAL_FDCAN_GetTxFifoFreeLevel(hfdcan) == 0) break; + if (!BSP_FDCAN_TxQueuePop(fdcan, &msg)) break; + HAL_StatusTypeDef res = HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &msg.header, msg.data); + if (res != HAL_OK) { + break; + } + } + } +} + +static void BSP_FDCAN_RxFifo0Callback(void) { + FDCAN_RxHeaderTypeDef rx_header; + uint8_t rx_data[BSP_FDCAN_MAX_DLC]; + for (int fdcan_idx = 0; fdcan_idx < BSP_FDCAN_NUM; fdcan_idx++) { + FDCAN_HandleTypeDef *hfdcan = BSP_FDCAN_GetHandle((BSP_FDCAN_t)fdcan_idx); + if (hfdcan == NULL) continue; + while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0) { + if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data) == HAL_OK) { + uint32_t original_id = (rx_header.IdType == FDCAN_STANDARD_ID) ? rx_header.Identifier&0x7ff : rx_header.Identifier&0x1fffffff; + BSP_FDCAN_FrameType_t frame_type = BSP_FDCAN_GetFrameType(&rx_header); + uint32_t parsed_id = BSP_FDCAN_ParseId(original_id, frame_type); + osMessageQueueId_t queue = BSP_FDCAN_FindQueue((BSP_FDCAN_t)fdcan_idx, parsed_id); + if (queue != NULL) { + BSP_FDCAN_Message_t msg; + msg.frame_type = frame_type; + msg.original_id = original_id; + msg.parsed_id = parsed_id; + uint8_t real_len = fdcan_dlc2len[rx_header.DataLength & 0xF]; + msg.dlc = real_len; + if (msg.dlc > BSP_FDCAN_MAX_DLC) msg.dlc = BSP_FDCAN_MAX_DLC; + memset(msg.data, 0, BSP_FDCAN_MAX_DLC);//现在是最大缓冲区写法所以全清零 + memcpy(msg.data, rx_data, msg.dlc); + osMessageQueuePut(queue, &msg, 0, 0); + } + } else { + break; + } + } + } +} + +static void BSP_FDCAN_RxFifo1Callback(void) { + FDCAN_RxHeaderTypeDef rx_header; + uint8_t rx_data[BSP_FDCAN_MAX_DLC]; + for (int fdcan_idx = 0; fdcan_idx < BSP_FDCAN_NUM; fdcan_idx++) { + FDCAN_HandleTypeDef *hfdcan = BSP_FDCAN_GetHandle((BSP_FDCAN_t)fdcan_idx); + if (hfdcan == NULL) continue; + while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO1) > 0) { + if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO1, &rx_header, rx_data) == HAL_OK) { + uint32_t original_id = (rx_header.IdType == FDCAN_STANDARD_ID) ? rx_header.Identifier&0x7ff : rx_header.Identifier&0x1fffffff; + BSP_FDCAN_FrameType_t frame_type = BSP_FDCAN_GetFrameType(&rx_header); + uint32_t parsed_id = BSP_FDCAN_ParseId(original_id, frame_type); + osMessageQueueId_t queue = BSP_FDCAN_FindQueue((BSP_FDCAN_t)fdcan_idx, parsed_id); + if (queue != NULL) { + BSP_FDCAN_Message_t msg; + msg.frame_type = frame_type; + msg.original_id = original_id; + msg.parsed_id = parsed_id; + uint8_t real_len = fdcan_dlc2len[rx_header.DataLength & 0xF]; + msg.dlc = real_len; + if (msg.dlc > BSP_FDCAN_MAX_DLC) msg.dlc = BSP_FDCAN_MAX_DLC; + memset(msg.data, 0, BSP_FDCAN_MAX_DLC);//现在是最大缓冲区写法所以全清零 + memcpy(msg.data, rx_data, msg.dlc); + osMessageQueuePut(queue, &msg, 0, 0); + } + } else { + break; + } + } + } +} + +/* HAL Callback Stubs (map HAL FDCAN callbacks to user callbacks) */ +void HAL_FDCAN_TxEventFifoCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t TxEventFifoITs) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_EVENT_FIFO_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_EVENT_FIFO_CB](); + } +} + +void HAL_FDCAN_TxBufferCompleteCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndex) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_BUFFER_COMPLETE_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_BUFFER_COMPLETE_CB](); + } +} + +void HAL_FDCAN_TxBufferAbortCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndex) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_BUFFER_ABORT_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_BUFFER_ABORT_CB](); + } +} + +void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_RX_FIFO0_MSG_PENDING_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_RX_FIFO0_MSG_PENDING_CB](); + } +} + +void HAL_FDCAN_RxFifo1Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo1ITs) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_RX_FIFO1_MSG_PENDING_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_RX_FIFO1_MSG_PENDING_CB](); + } +} + +void HAL_FDCAN_ErrorCallback(FDCAN_HandleTypeDef *hfdcan) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_ERROR_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_ERROR_CB](); + } +} + +/* Exported functions ------------------------------------------------------- */ +int8_t BSP_FDCAN_Init(void) { + if (inited) return BSP_ERR_INITED; + + memset(FDCAN_Callback, 0, sizeof(FDCAN_Callback)); + for (int i = 0; i < BSP_FDCAN_NUM; i++) BSP_FDCAN_TxQueueInit((BSP_FDCAN_t)i); + id_parser = BSP_FDCAN_DefaultIdParser; + queue_mutex = osMutexNew(NULL); + if (queue_mutex == NULL) return BSP_ERR; + + inited = true; + + /* 配置并启动 FDCAN 实例,绑定中断/回调 */ + + //========== 过滤器配置说明:========================== + // 过滤器编号:相对于每个(相当于经典can过滤器的bank) + // sFilterConfig.FilterIndex = 0 to 127(标准ID) or 0 to 63(扩展ID); + // 关于过滤器索引的说明: + // 由stm32h7xx_hal_fdcan.c的第1874行代码可知滤波器地址计算方式如下: + // StandardFilterSA(字节) = SRAMCAN_BASE + (MessageRAMOffset * 4U) + // 标准滤波器物理地址(字节) = StandardFilterSA + (FilterIndex * 4U)(每个标准滤波器占 4 字节 = 1 word,扩展的则是8个字节) + // + // + // 标识符类型: + // sFilterConfig.IdType = FDCAN_STANDARD_ID or FDCAN_EXTENDED_ID; + // 过滤器类型: (仅介绍掩码模式) + // sFilterConfig.FilterType = FDCAN_FILTER_MASK;(掩码模式) + // 过滤器配置: + // sFilterConfig.FilterConfig = FDCAN_FILTER_DISABLE; (禁用该过滤器条目) + // FDCAN_FILTER_TO_RXFIFO0; (将匹配的消息放入 FIFO 0(普通优先级)) + // FDCAN_FILTER_TO_RXFIFO1; (将匹配的消息放入 FIFO 1(高优先级)) + // FDCAN_FILTER_TO_RXBUFFER; (将匹配的消息放入 指定的接收缓冲区) + // FDCAN_FILTER_REJECT; (拒绝接收该标识符对应的报文) + // FDCAN_FILTER_ACCEPT; (接受所有消息) + // FDCAN_FILTER_HP (过滤器匹配时,将报文标记为高优先级) + // FDCAN_FILTER_TO_RXFIFO0_HP (过滤器匹配时,将报文标记为高优先级并存储至接收FIFO 0) + // FDCAN_FILTER_TO_RXFIFO1_HP (过滤器匹配时,将报文标记为高优先级并存储至接收FIFO 1) + // FDCAN_FILTER_TO_RXBUFFER (将报文存储至接收缓冲区,过滤器类型(FilterType)配置项失效 ) + // 过滤器ID与掩码(FilterType掩码模式下) + // 比较值(要匹配的 ID 的参考位) + // sFilterConfig.FilterID1 = 0 to 0x7FF; 标准ID + // 0 to 0x1FFFFFFF 扩展ID + // 掩码(1=比较该位,0=忽略该位) + // sFilterConfig.FilterID2 = 0 to 0x7FF; 标准ID + // 0 to 0x1FFFFFFF 扩展ID + // 接收缓冲区索引 + // FilterConfig == FDCAN_FILTER_TO_RXBUFFER 时有效;必须小于RxBuffersNbr配置的实际Rx buffer数量 + // sFilterConfig.RxBufferIndex = 0 to (RxBuffersNbr - 1); + // 标记校准信息(用于 FDCAN 校准/时钟相关单元作特殊处理或统计) + // 仅在FilterConfig 设为 FDCAN_FILTER_TO_RXBUFFER 时才有意义,通常设置为0 + // IsCalibrationMsg = 0 or 1; + // fdcan_filter_table.h + //================================================================================= + /* 依据上述说明,配置过滤器并启动FDCAN */ + FDCAN_FilterTypeDef sFilterConfig; + +#ifdef FDCAN1_EN + #define hfdcan hfdcan1 + #define FDCANX_RX_FIFO FDCAN1_RX_FIFO + FDCAN1_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER) + #undef hfdcan + #undef FDCANX_RX_FIFO + HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN1_GLOBAL_FILTER); + HAL_FDCAN_ActivateNotification(&hfdcan1, FDCANx_NOTIFY_FLAGS(FDCAN1_RX_FIFO), 0); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_1, FDCANX_MSG_PENDING_CB(FDCAN1_RX_FIFO), BSP_FDCAN_RxFifo0Callback); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_1, HAL_FDCAN_TX_EVENT_FIFO_CB, BSP_FDCAN_TxCompleteCallback); + HAL_FDCAN_Start(&hfdcan1); +#endif + +#ifdef FDCAN2_EN + #define hfdcan hfdcan2 + #define FDCANX_RX_FIFO FDCAN2_RX_FIFO + FDCAN2_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER) + #undef hfdcan + #undef FDCANX_RX_FIFO + HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN2_GLOBAL_FILTER); + HAL_FDCAN_ActivateNotification(&hfdcan2, FDCANx_NOTIFY_FLAGS(FDCAN2_RX_FIFO), 0); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_2, FDCANX_MSG_PENDING_CB(FDCAN2_RX_FIFO), BSP_FDCAN_RxFifo1Callback); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_2, HAL_FDCAN_TX_EVENT_FIFO_CB, BSP_FDCAN_TxCompleteCallback); + HAL_FDCAN_Start(&hfdcan2); +#endif + +#ifdef FDCAN3_EN + #define hfdcan hfdcan3 + #define FDCANX_RX_FIFO FDCAN3_RX_FIFO + FDCAN3_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER) + #undef hfdcan + #undef FDCANX_RX_FIFO + HAL_FDCAN_ConfigGlobalFilter(&hfdcan3, FDCAN3_GLOBAL_FILTER); + HAL_FDCAN_ActivateNotification(&hfdcan3, FDCANx_NOTIFY_FLAGS(FDCAN3_RX_FIFO), 0); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_3, FDCANX_MSG_PENDING_CB(FDCAN3_RX_FIFO), BSP_FDCAN_RxFifo1Callback); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_3, HAL_FDCAN_TX_EVENT_FIFO_CB, BSP_FDCAN_TxCompleteCallback); + HAL_FDCAN_Start(&hfdcan3); +#endif + +#undef FDCAN_FILTER_TO_RXFIFO_ENUM_INNER +#undef FDCAN_FILTER_TO_RXFIFO_ENUM +#undef FDCAN_CONFIG_FILTER +#undef FDCAN_NOTIFY_FLAG_RXFIFO_INNER +#undef FDCAN_NOTIFY_FLAG_RXFIFO +#undef FDCANx_NOTIFY_FLAGS +#undef FDCANX_MSG_PENDING_CB_INNER +#undef FDCANX_MSG_PENDING_CB + + return BSP_OK; +} + +FDCAN_HandleTypeDef *BSP_FDCAN_GetHandle(BSP_FDCAN_t fdcan) { + if (fdcan >= BSP_FDCAN_NUM) return NULL; + switch (fdcan) { + /* AUTO GENERATED BSP_FDCAN_GET_HANDLE BEGIN */ + case BSP_FDCAN_1: return &hfdcan1; + case BSP_FDCAN_2: return &hfdcan2; + case BSP_FDCAN_3: return &hfdcan3; + /* AUTO GENERATED BSP_FDCAN_GET_HANDLE END */ + default: return NULL; + } +} + +int8_t BSP_FDCAN_RegisterCallback(BSP_FDCAN_t fdcan, BSP_FDCAN_Callback_t type, void (*callback)(void)) { + if (!inited) return BSP_ERR_INITED; + if (callback == NULL) return BSP_ERR_NULL; + if (fdcan >= BSP_FDCAN_NUM) return BSP_ERR; + if (type >= HAL_FDCAN_CB_NUM) return BSP_ERR; + FDCAN_Callback[fdcan][type] = callback; + return BSP_OK; +} + +int8_t BSP_FDCAN_Transmit(BSP_FDCAN_t fdcan, BSP_FDCAN_Format_t format, uint32_t id, uint8_t *data, uint8_t dlc) { + if (!inited) return BSP_ERR_INITED; + if (fdcan >= BSP_FDCAN_NUM) return BSP_ERR; + if (data == NULL && format != BSP_FDCAN_FORMAT_STD_REMOTE && format != BSP_FDCAN_FORMAT_EXT_REMOTE) return BSP_ERR_NULL; + if (dlc > BSP_FDCAN_MAX_DLC) return BSP_ERR; + FDCAN_HandleTypeDef *hfdcan = BSP_FDCAN_GetHandle(fdcan); + if (hfdcan == NULL) return BSP_ERR_NULL; + + BSP_FDCAN_TxMessage_t tx_msg = {0}; + switch (format) { + case BSP_FDCAN_FORMAT_STD_DATA: + tx_msg.header.Identifier = id; + tx_msg.header.IdType = FDCAN_STANDARD_ID; + tx_msg.header.TxFrameType = FDCAN_DATA_FRAME; + break; + case BSP_FDCAN_FORMAT_EXT_DATA: + tx_msg.header.Identifier = id; + tx_msg.header.IdType = FDCAN_EXTENDED_ID; + tx_msg.header.TxFrameType = FDCAN_DATA_FRAME; + break; + case BSP_FDCAN_FORMAT_STD_REMOTE: + tx_msg.header.Identifier = id; + tx_msg.header.IdType = FDCAN_STANDARD_ID; + tx_msg.header.TxFrameType = FDCAN_REMOTE_FRAME; + break; + case BSP_FDCAN_FORMAT_EXT_REMOTE: + tx_msg.header.Identifier = id; + tx_msg.header.IdType = FDCAN_EXTENDED_ID; + tx_msg.header.TxFrameType = FDCAN_REMOTE_FRAME; + break; + default: + return BSP_ERR; + } + switch (hfdcan->Init.FrameFormat) { + case FDCAN_FRAME_FD_BRS: + tx_msg.header.BitRateSwitch = FDCAN_BRS_ON; + tx_msg.header.FDFormat = FDCAN_FD_CAN; + break; + case FDCAN_FRAME_FD_NO_BRS: + tx_msg.header.BitRateSwitch = FDCAN_BRS_OFF; + tx_msg.header.FDFormat = FDCAN_FD_CAN; + break; + case FDCAN_FRAME_CLASSIC: + default: + tx_msg.header.BitRateSwitch = FDCAN_BRS_OFF; + tx_msg.header.FDFormat = FDCAN_CLASSIC_CAN; + break; + } + tx_msg.header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; + tx_msg.header.TxEventFifoControl = FDCAN_STORE_TX_EVENTS; + tx_msg.header.MessageMarker = 0x01; + tx_msg.header.DataLength = BSP_FDCAN_EncodeDLC(dlc); + + memset(tx_msg.data, 0, dlc); + if (data != NULL && dlc > 0) {memcpy(tx_msg.data, data, dlc);} + + if (HAL_FDCAN_GetTxFifoFreeLevel(hfdcan) > 0) { + if (HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &tx_msg.header, tx_msg.data) == HAL_OK) return BSP_OK; + } + if (BSP_FDCAN_TxQueuePush(fdcan, &tx_msg)) return BSP_OK; + return BSP_ERR; +} + +int8_t BSP_FDCAN_TransmitStdDataFrame(BSP_FDCAN_t fdcan, BSP_FDCAN_StdDataFrame_t *frame) { + if (frame == NULL) return BSP_ERR_NULL; + return BSP_FDCAN_Transmit(fdcan, BSP_FDCAN_FORMAT_STD_DATA, frame->id, frame->data, frame->dlc); +} + +int8_t BSP_FDCAN_TransmitExtDataFrame(BSP_FDCAN_t fdcan, BSP_FDCAN_ExtDataFrame_t *frame) { + if (frame == NULL) return BSP_ERR_NULL; + return BSP_FDCAN_Transmit(fdcan, BSP_FDCAN_FORMAT_EXT_DATA, frame->id, frame->data, frame->dlc); +} + +int8_t BSP_FDCAN_TransmitRemoteFrame(BSP_FDCAN_t fdcan, BSP_FDCAN_RemoteFrame_t *frame) { + if (frame == NULL) return BSP_ERR_NULL; + BSP_FDCAN_Format_t format = frame->is_extended ? BSP_FDCAN_FORMAT_EXT_REMOTE : BSP_FDCAN_FORMAT_STD_REMOTE; + return BSP_FDCAN_Transmit(fdcan, format, frame->id, NULL, frame->dlc); +} + +int8_t BSP_FDCAN_RegisterId(BSP_FDCAN_t fdcan, uint32_t can_id, uint8_t queue_size) { + if (!inited) return BSP_ERR_INITED; + return BSP_FDCAN_CreateIdQueue(fdcan, can_id, queue_size); +} + +int8_t BSP_FDCAN_GetMessage(BSP_FDCAN_t fdcan, uint32_t can_id, BSP_FDCAN_Message_t *msg, uint32_t timeout) { + if (!inited) return BSP_ERR_INITED; + if (msg == NULL) return BSP_ERR_NULL; + if (osMutexAcquire(queue_mutex, FDCAN_QUEUE_MUTEX_TIMEOUT) != osOK) return BSP_ERR_TIMEOUT; + osMessageQueueId_t queue = BSP_FDCAN_FindQueue(fdcan, can_id); + osMutexRelease(queue_mutex); + if (queue == NULL) return BSP_ERR_NO_DEV; + osStatus_t res = osMessageQueueGet(queue, msg, NULL, timeout); + return (res == osOK) ? BSP_OK : BSP_ERR; +} + +int32_t BSP_FDCAN_GetQueueCount(BSP_FDCAN_t fdcan, uint32_t can_id) { + if (!inited) return -1; + if (osMutexAcquire(queue_mutex, FDCAN_QUEUE_MUTEX_TIMEOUT) != osOK) return -1; + osMessageQueueId_t queue = BSP_FDCAN_FindQueue(fdcan, can_id); + osMutexRelease(queue_mutex); + if (queue == NULL) return -1; + return (int32_t)osMessageQueueGetCount(queue); +} + +int8_t BSP_FDCAN_FlushQueue(BSP_FDCAN_t fdcan, uint32_t can_id) { + if (!inited) return BSP_ERR_INITED; + if (osMutexAcquire(queue_mutex, FDCAN_QUEUE_MUTEX_TIMEOUT) != osOK) return BSP_ERR_TIMEOUT; + osMessageQueueId_t queue = BSP_FDCAN_FindQueue(fdcan, can_id); + osMutexRelease(queue_mutex); + if (queue == NULL) return BSP_ERR_NO_DEV; + BSP_FDCAN_Message_t tmp; + while (osMessageQueueGet(queue, &tmp, NULL, BSP_FDCAN_TIMEOUT_IMMEDIATE) == osOK) { } + return BSP_OK; +} + +int8_t BSP_FDCAN_RegisterIdParser(BSP_FDCAN_IdParser_t parser) { + if (!inited) return BSP_ERR_INITED; + if (parser == NULL) return BSP_ERR_NULL; + id_parser = parser; + return BSP_OK; +} + +uint32_t BSP_FDCAN_ParseId(uint32_t original_id, BSP_FDCAN_FrameType_t frame_type) { + if (id_parser != NULL) return id_parser(original_id, frame_type); + return BSP_FDCAN_DefaultIdParser(original_id, frame_type); +} +/* */ + diff --git a/assets/User_code/bsp/fdcan.h b/assets/User_code/bsp/fdcan.h new file mode 100644 index 0000000..99ecd80 --- /dev/null +++ b/assets/User_code/bsp/fdcan.h @@ -0,0 +1,137 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ----------------------------------------------------------------- */ +#include +#include +#include "bsp/bsp.h" +#include "bsp/mm.h" +#include + +/* USER INCLUDE BEGIN */ +#include +/* USER INCLUDE END */ + +/* Exported constants ------------------------------------------------------- */ +#define BSP_FDCAN_MAX_DLC 64 +#define BSP_FDCAN_DEFAULT_QUEUE_SIZE 10 +#define BSP_FDCAN_TIMEOUT_IMMEDIATE 0 +#define BSP_FDCAN_TIMEOUT_FOREVER osWaitForever +#define BSP_FDCAN_TX_QUEUE_SIZE 32 +/* Exported macro ----------------------------------------------------------- */ +//FDCANX实例使能 +/* AUTO GENERATED FDCAN_EN BEGIN */ +#define FDCAN1_EN +#define FDCAN2_EN +#define FDCAN3_EN +/* AUTO GENERATED FDCAN_EN END */ + +// FDCANX接收FIFO选择(0=FIFO0, 1=FIFO1) +/* AUTO GENERATED FDCAN_RX_FIFO BEGIN */ +#ifdef FDCAN1_EN + #define FDCAN1_RX_FIFO 0 +#endif +#ifdef FDCAN2_EN + #define FDCAN2_RX_FIFO 1 +#endif +#ifdef FDCAN3_EN + #define FDCAN3_RX_FIFO 1 +#endif +/* AUTO GENERATED FDCAN_RX_FIFO END */ +/* Exported types ----------------------------------------------------------- */ +typedef enum { + /* AUTO GENERATED BSP_FDCAN_NAME BEGIN */ + BSP_FDCAN_1, + BSP_FDCAN_2, + BSP_FDCAN_3, + /* AUTO GENERATED BSP_FDCAN_NAME END */ + BSP_FDCAN_NUM, + BSP_FDCAN_ERR, +} BSP_FDCAN_t; + +typedef enum { + HAL_FDCAN_TX_EVENT_FIFO_CB, + HAL_FDCAN_TX_BUFFER_COMPLETE_CB, + HAL_FDCAN_TX_BUFFER_ABORT_CB, + HAL_FDCAN_RX_FIFO0_MSG_PENDING_CB, + HAL_FDCAN_RX_FIFO0_FULL_CB, + HAL_FDCAN_RX_FIFO1_MSG_PENDING_CB, + HAL_FDCAN_RX_FIFO1_FULL_CB, + HAL_FDCAN_ERROR_CB, + HAL_FDCAN_CB_NUM, +} BSP_FDCAN_Callback_t; + +typedef enum { + BSP_FDCAN_FORMAT_STD_DATA, + BSP_FDCAN_FORMAT_EXT_DATA, + BSP_FDCAN_FORMAT_STD_REMOTE, + BSP_FDCAN_FORMAT_EXT_REMOTE, +} BSP_FDCAN_Format_t; + +typedef enum { + BSP_FDCAN_FRAME_STD_DATA, + BSP_FDCAN_FRAME_EXT_DATA, + BSP_FDCAN_FRAME_STD_REMOTE, + BSP_FDCAN_FRAME_EXT_REMOTE, +} BSP_FDCAN_FrameType_t; + +typedef struct { + BSP_FDCAN_FrameType_t frame_type; + uint32_t original_id; + uint32_t parsed_id; + uint8_t dlc; + uint8_t data[BSP_FDCAN_MAX_DLC]; + uint32_t timestamp; +} BSP_FDCAN_Message_t; + +typedef struct { + uint32_t id; + uint8_t dlc; + uint8_t data[BSP_FDCAN_MAX_DLC]; +} BSP_FDCAN_StdDataFrame_t; + +typedef struct { + uint32_t id; + uint8_t dlc; + uint8_t data[BSP_FDCAN_MAX_DLC]; +} BSP_FDCAN_ExtDataFrame_t; + +typedef struct { + uint32_t id; + uint8_t dlc; + bool is_extended; +} BSP_FDCAN_RemoteFrame_t; + +typedef uint32_t (*BSP_FDCAN_IdParser_t)(uint32_t original_id, BSP_FDCAN_FrameType_t frame_type); + +typedef struct { + FDCAN_TxHeaderTypeDef header; /* HAL FDCAN header type */ + uint8_t data[BSP_FDCAN_MAX_DLC]; +} BSP_FDCAN_TxMessage_t; + +typedef struct { + BSP_FDCAN_TxMessage_t buffer[BSP_FDCAN_TX_QUEUE_SIZE]; + volatile uint32_t head; + volatile uint32_t tail; +} BSP_FDCAN_TxQueue_t; + +/* Exported functions prototypes -------------------------------------------- */ +int8_t BSP_FDCAN_Init(void); +FDCAN_HandleTypeDef *BSP_FDCAN_GetHandle(BSP_FDCAN_t can); +int8_t BSP_FDCAN_RegisterCallback(BSP_FDCAN_t can, BSP_FDCAN_Callback_t type, void (*callback)(void)); +int8_t BSP_FDCAN_Transmit(BSP_FDCAN_t can, BSP_FDCAN_Format_t format, uint32_t id, uint8_t *data, uint8_t dlc); +int8_t BSP_FDCAN_TransmitStdDataFrame(BSP_FDCAN_t can, BSP_FDCAN_StdDataFrame_t *frame); +int8_t BSP_FDCAN_TransmitExtDataFrame(BSP_FDCAN_t can, BSP_FDCAN_ExtDataFrame_t *frame); +int8_t BSP_FDCAN_TransmitRemoteFrame(BSP_FDCAN_t can, BSP_FDCAN_RemoteFrame_t *frame); +int8_t BSP_FDCAN_RegisterId(BSP_FDCAN_t can, uint32_t can_id, uint8_t queue_size); +int8_t BSP_FDCAN_GetMessage(BSP_FDCAN_t can, uint32_t can_id, BSP_FDCAN_Message_t *msg, uint32_t timeout); +int32_t BSP_FDCAN_GetQueueCount(BSP_FDCAN_t can, uint32_t can_id); +int8_t BSP_FDCAN_FlushQueue(BSP_FDCAN_t can, uint32_t can_id); +int8_t BSP_FDCAN_RegisterIdParser(BSP_FDCAN_IdParser_t parser); +uint32_t BSP_FDCAN_ParseId(uint32_t original_id, BSP_FDCAN_FrameType_t frame_type); +#ifdef __cplusplus +} +#endif diff --git a/assets/User_code/config.csv b/assets/User_code/config.csv index 32290e1..878ede2 100644 --- a/assets/User_code/config.csv +++ b/assets/User_code/config.csv @@ -1,4 +1,4 @@ -bsp,can,dwt,gpio,i2c,mm,spi,uart,pwm,time +bsp,can,fdcan,dwt,gpio,i2c,mm,spi,uart,pwm,time component,ahrs,capacity,cmd,crc8,crc16,error_detect,filter,FreeRTOS_CLI,limiter,mixer,pid,ui,user_math device,dr16,bmi088,ist8310,motor,motor_rm,motor_dm,motor_vesc,motor_lk,motor_lz,motor_odrive,dm_imu,rc_can,servo,buzzer,led,ws2812,vofa,ops9 module,config, \ No newline at end of file