bin/chuankou/Sendmsg.classBinary files differ
bin/chuankou/SerialDataReceiver.classBinary files differ
bin/chushihua/lunxun$PollingTask.classBinary files differ
bin/chushihua/lunxun.classBinary files differ
bin/publicway/ProtocolParser01$CardStatus.classBinary files differ
bin/publicway/ProtocolParser01$DoorStatus.classBinary files differ
bin/publicway/ProtocolParser01$FaultType.classBinary files differ
bin/publicway/ProtocolParser01$ParseResult.classBinary files differ
bin/publicway/ProtocolParser01$ParseResultPool.classBinary files differ
bin/publicway/ProtocolParser01$WorkStatus.classBinary files differ
bin/publicway/ProtocolParser01.classBinary files differ
bin/publicway/SerialProtocolParser.classBinary files differ
bin/xitongshezhi/kuaisuquka$2.classBinary files differ
bin/xitongshezhi/kuaisuquka$3.classBinary files differ
bin/xitongshezhi/kuaisuquka$4.classBinary files differ
bin/xitongshezhi/kuaisuquka$SlotButtonListener.classBinary files differ
bin/xitongshezhi/kuaisuquka.classBinary files differ
log.properties
@@ -1,267 +1,33 @@ #\u64CD\u4F5C\u65E5\u5FD7\u8BB0\u5F55 - \u6700\u540E\u66F4\u65B0: Fri Nov 21 17:13:04 CST 2025 #Fri Nov 21 17:13:04 CST 2025 log_1763709005376_be67189d=[2025-11-21 15\:10\:05] 取卡操作:卡槽14被管理员取卡 log_1763709010792_533f9544=[2025-11-21 15\:10\:10] 取卡操作:卡槽14被管理员取卡 log_1763710366394_3e2ee73b=[2025-11-21 15\:32\:46] 取卡操作:卡槽1被管理员取卡 log_1763710369073_b9adfbaf=[2025-11-21 15\:32\:49] 管理员已将全部卡槽已经打开请取卡 log_1763710369761_bb324453=[2025-11-21 15\:32\:49] 取卡操作:卡槽2被管理员取卡 log_1763710374805_729bf4a3=[2025-11-21 15\:32\:54] 取卡操作:卡槽3被管理员取卡 log_1763710376872_53e825d5=[2025-11-21 15\:32\:56] 取卡操作:卡槽4被管理员取卡 log_1763710377434_30d03572=[2025-11-21 15\:32\:57] 取卡操作:卡槽5被管理员取卡 log_1763710377702_d982793b=[2025-11-21 15\:32\:57] 取卡操作:卡槽6被管理员取卡 log_1763710378251_dcba47b6=[2025-11-21 15\:32\:58] 取卡操作:卡槽7被管理员取卡 log_1763710378740_621c7d16=[2025-11-21 15\:32\:58] 取卡操作:卡槽8被管理员取卡 log_1763710378945_1f90633a=[2025-11-21 15\:32\:58] 取卡操作:卡槽9被管理员取卡 log_1763710379551_0d57ca92=[2025-11-21 15\:32\:59] 取卡操作:卡槽10被管理员取卡 log_1763710379765_c62a1f70=[2025-11-21 15\:32\:59] 取卡操作:卡槽11被管理员取卡 log_1763710380759_1a3f3a2d=[2025-11-21 15\:33\:00] 取卡操作:卡槽12被管理员取卡 log_1763710381303_43876449=[2025-11-21 15\:33\:01] 取卡操作:卡槽13被管理员取卡 log_1763710381490_e2f23d01=[2025-11-21 15\:33\:01] 取卡操作:卡槽14被管理员取卡 log_1763710381832_64ae1479=[2025-11-21 15\:33\:01] 取卡操作:卡槽15被管理员取卡 log_1763710382171_5447584c=[2025-11-21 15\:33\:02] 取卡操作:卡槽16被管理员取卡 log_1763710382679_028e4b55=[2025-11-21 15\:33\:02] 取卡操作:卡槽17被管理员取卡 log_1763710383184_87fbec0b=[2025-11-21 15\:33\:03] 取卡操作:卡槽18被管理员取卡 log_1763710383706_a4cf4dc7=[2025-11-21 15\:33\:03] 取卡操作:卡槽19被管理员取卡 log_1763710383969_ee1134f4=[2025-11-21 15\:33\:03] 取卡操作:卡槽20被管理员取卡 log_1763710384261_24848bed=[2025-11-21 15\:33\:04] 取卡操作:卡槽21被管理员取卡 log_1763710384754_dd683aa4=[2025-11-21 15\:33\:04] 取卡操作:卡槽22被管理员取卡 log_1763710385236_cb72df23=[2025-11-21 15\:33\:05] 取卡操作:卡槽23被管理员取卡 log_1763710385688_59448adc=[2025-11-21 15\:33\:05] 取卡操作:卡槽24被管理员取卡 log_1763710385869_5cd15f66=[2025-11-21 15\:33\:05] 取卡操作:卡槽25被管理员取卡 log_1763710386114_b27f7cdb=[2025-11-21 15\:33\:06] 取卡操作:卡槽26被管理员取卡 log_1763710386353_207e922a=[2025-11-21 15\:33\:06] 取卡操作:卡槽27被管理员取卡 log_1763710386567_dedb947b=[2025-11-21 15\:33\:06] 取卡操作:卡槽28被管理员取卡 log_1763710386774_fdb60ca6=[2025-11-21 15\:33\:06] 取卡操作:卡槽29被管理员取卡 log_1763710387277_ec9fe131=[2025-11-21 15\:33\:07] 取卡操作:卡槽30被管理员取卡 log_1763710392318_2b9de060=[2025-11-21 15\:33\:12] 取卡操作:卡槽31被管理员取卡 log_1763710394899_2c102a5d=[2025-11-21 15\:33\:14] 取卡操作:卡槽32被管理员取卡 log_1763710395618_9580d0cf=[2025-11-21 15\:33\:15] 取卡操作:卡槽33被管理员取卡 log_1763710395824_c45c4bb7=[2025-11-21 15\:33\:15] 取卡操作:卡槽34被管理员取卡 log_1763710396024_19f89ff8=[2025-11-21 15\:33\:16] 取卡操作:卡槽35被管理员取卡 log_1763710396205_1e9f3544=[2025-11-21 15\:33\:16] 取卡操作:卡槽36被管理员取卡 log_1763710396395_09793aa0=[2025-11-21 15\:33\:16] 取卡操作:卡槽37被管理员取卡 log_1763710396586_6da2a2be=[2025-11-21 15\:33\:16] 取卡操作:卡槽38被管理员取卡 log_1763710396751_27627af1=[2025-11-21 15\:33\:16] 取卡操作:卡槽39被管理员取卡 log_1763710396925_048a1d33=[2025-11-21 15\:33\:16] 取卡操作:卡槽40被管理员取卡 log_1763710397700_9009fb44=[2025-11-21 15\:33\:17] 取卡操作:卡槽41被管理员取卡 log_1763710398160_e8f79aa9=[2025-11-21 15\:33\:18] 取卡操作:卡槽42被管理员取卡 log_1763710398344_dba27f5c=[2025-11-21 15\:33\:18] 取卡操作:卡槽43被管理员取卡 log_1763710398527_84a6586d=[2025-11-21 15\:33\:18] 取卡操作:卡槽44被管理员取卡 log_1763710398709_ca4898fa=[2025-11-21 15\:33\:18] 取卡操作:卡槽45被管理员取卡 log_1763710398891_21c16b85=[2025-11-21 15\:33\:18] 取卡操作:卡槽46被管理员取卡 log_1763710399064_7a60cb4f=[2025-11-21 15\:33\:19] 取卡操作:卡槽47被管理员取卡 log_1763710399256_d1754fdf=[2025-11-21 15\:33\:19] 取卡操作:卡槽48被管理员取卡 log_1763710399440_adfb38c2=[2025-11-21 15\:33\:19] 取卡操作:卡槽49被管理员取卡 log_1763710399628_25b129e2=[2025-11-21 15\:33\:19] 取卡操作:卡槽50被管理员取卡 log_1763710399804_bfdf1f49=[2025-11-21 15\:33\:19] 取卡操作:卡槽51被管理员取卡 log_1763710399981_9a6fae3a=[2025-11-21 15\:33\:19] 取卡操作:卡槽52被管理员取卡 log_1763710400191_f4c40a9a=[2025-11-21 15\:33\:20] 取卡操作:卡槽53被管理员取卡 log_1763710400361_300e2593=[2025-11-21 15\:33\:20] 取卡操作:卡槽54被管理员取卡 log_1763710400545_ae5dd8e4=[2025-11-21 15\:33\:20] 取卡操作:卡槽55被管理员取卡 log_1763710400735_0041b12f=[2025-11-21 15\:33\:20] 取卡操作:卡槽56被管理员取卡 log_1763710401100_1951843e=[2025-11-21 15\:33\:21] 取卡操作:卡槽57被管理员取卡 log_1763710401283_580b32ee=[2025-11-21 15\:33\:21] 取卡操作:卡槽58被管理员取卡 log_1763710401476_d0cee988=[2025-11-21 15\:33\:21] 取卡操作:卡槽59被管理员取卡 log_1763710401684_bfb7a541=[2025-11-21 15\:33\:21] 取卡操作:卡槽60被管理员取卡 log_1763710738513_bc5737ed=[2025-11-21 15\:38\:58] 取卡操作:卡槽1被管理员取卡 log_1763710739297_f16f6cbf=[2025-11-21 15\:38\:59] 管理员已将全部卡槽已经打开请取卡 log_1763710743588_a44dd2b1=[2025-11-21 15\:39\:03] 取卡操作:卡槽2被管理员取卡 log_1763710745191_e7cd7335=[2025-11-21 15\:39\:05] 取卡操作:卡槽3被管理员取卡 log_1763710745941_38917a60=[2025-11-21 15\:39\:05] 取卡操作:卡槽4被管理员取卡 log_1763710746428_1be0c2ec=[2025-11-21 15\:39\:06] 取卡操作:卡槽5被管理员取卡 log_1763710746617_a7f4572b=[2025-11-21 15\:39\:06] 取卡操作:卡槽6被管理员取卡 log_1763710746844_6dccbbfa=[2025-11-21 15\:39\:06] 取卡操作:卡槽7被管理员取卡 log_1763710747030_7f129941=[2025-11-21 15\:39\:07] 取卡操作:卡槽8被管理员取卡 log_1763710747475_7008b86e=[2025-11-21 15\:39\:07] 取卡操作:卡槽9被管理员取卡 log_1763710747663_5bcece5b=[2025-11-21 15\:39\:07] 取卡操作:卡槽10被管理员取卡 log_1763710747839_836fdc15=[2025-11-21 15\:39\:07] 取卡操作:卡槽11被管理员取卡 log_1763710748297_819cb00d=[2025-11-21 15\:39\:08] 取卡操作:卡槽12被管理员取卡 log_1763710748481_d62eee38=[2025-11-21 15\:39\:08] 取卡操作:卡槽13被管理员取卡 log_1763710748713_7e8e1b78=[2025-11-21 15\:39\:08] 取卡操作:卡槽14被管理员取卡 log_1763710748924_6eb58529=[2025-11-21 15\:39\:08] 取卡操作:卡槽15被管理员取卡 log_1763710749180_b4f93c07=[2025-11-21 15\:39\:09] 取卡操作:卡槽16被管理员取卡 log_1763710749430_d4374f53=[2025-11-21 15\:39\:09] 取卡操作:卡槽17被管理员取卡 log_1763710749722_871e5938=[2025-11-21 15\:39\:09] 取卡操作:卡槽18被管理员取卡 log_1763710749929_a7b4b17c=[2025-11-21 15\:39\:09] 取卡操作:卡槽19被管理员取卡 log_1763710750112_41fe9c56=[2025-11-21 15\:39\:10] 取卡操作:卡槽20被管理员取卡 log_1763710750309_c9445b6a=[2025-11-21 15\:39\:10] 取卡操作:卡槽21被管理员取卡 log_1763710750497_dbfb3b50=[2025-11-21 15\:39\:10] 取卡操作:卡槽22被管理员取卡 log_1763710750865_8b47fb9d=[2025-11-21 15\:39\:10] 取卡操作:卡槽23被管理员取卡 log_1763710751038_58cc3a3b=[2025-11-21 15\:39\:11] 取卡操作:卡槽24被管理员取卡 log_1763710751222_50d2ca7f=[2025-11-21 15\:39\:11] 取卡操作:卡槽25被管理员取卡 log_1763710751396_e0d7e4d4=[2025-11-21 15\:39\:11] 取卡操作:卡槽26被管理员取卡 log_1763710751576_c31a2bb8=[2025-11-21 15\:39\:11] 取卡操作:卡槽27被管理员取卡 log_1763710751759_3257dff6=[2025-11-21 15\:39\:11] 取卡操作:卡槽28被管理员取卡 log_1763710751933_5b98b5b1=[2025-11-21 15\:39\:11] 取卡操作:卡槽29被管理员取卡 log_1763710752106_c249e495=[2025-11-21 15\:39\:12] 取卡操作:卡槽30被管理员取卡 log_1763710752288_3473b11e=[2025-11-21 15\:39\:12] 取卡操作:卡槽31被管理员取卡 log_1763710752478_bddf4a0f=[2025-11-21 15\:39\:12] 取卡操作:卡槽32被管理员取卡 log_1763710752678_03b7b598=[2025-11-21 15\:39\:12] 取卡操作:卡槽33被管理员取卡 log_1763710752882_cead4734=[2025-11-21 15\:39\:12] 取卡操作:卡槽34被管理员取卡 log_1763710753096_3e58465d=[2025-11-21 15\:39\:13] 取卡操作:卡槽35被管理员取卡 log_1763710753294_c8a39f42=[2025-11-21 15\:39\:13] 取卡操作:卡槽36被管理员取卡 log_1763710753795_011f5c48=[2025-11-21 15\:39\:13] 取卡操作:卡槽37被管理员取卡 log_1763710753999_a6bdf722=[2025-11-21 15\:39\:13] 取卡操作:卡槽38被管理员取卡 log_1763710754230_c6b37d6c=[2025-11-21 15\:39\:14] 取卡操作:卡槽39被管理员取卡 log_1763710754429_5a2cf0e3=[2025-11-21 15\:39\:14] 取卡操作:卡槽40被管理员取卡 log_1763710754634_524e289c=[2025-11-21 15\:39\:14] 取卡操作:卡槽41被管理员取卡 log_1763710754833_e252c751=[2025-11-21 15\:39\:14] 取卡操作:卡槽42被管理员取卡 log_1763710755046_ca4fdaed=[2025-11-21 15\:39\:15] 取卡操作:卡槽43被管理员取卡 log_1763710755245_f0a4c432=[2025-11-21 15\:39\:15] 取卡操作:卡槽44被管理员取卡 log_1763710755433_66d05da5=[2025-11-21 15\:39\:15] 取卡操作:卡槽45被管理员取卡 log_1763710755608_b2636ea5=[2025-11-21 15\:39\:15] 取卡操作:卡槽46被管理员取卡 log_1763710760647_d7b2c8f0=[2025-11-21 15\:39\:20] 取卡操作:卡槽47被管理员取卡 log_1763710765684_8d3d2ecb=[2025-11-21 15\:39\:25] 取卡操作:卡槽48被管理员取卡 log_1763710770722_8f84c7e9=[2025-11-21 15\:39\:30] 取卡操作:卡槽49被管理员取卡 log_1763710775759_33513110=[2025-11-21 15\:39\:35] 取卡操作:卡槽50被管理员取卡 log_1763710780797_bca992a2=[2025-11-21 15\:39\:40] 取卡操作:卡槽51被管理员取卡 log_1763710785835_7036b416=[2025-11-21 15\:39\:45] 取卡操作:卡槽52被管理员取卡 log_1763710790878_14c5f190=[2025-11-21 15\:39\:50] 取卡操作:卡槽53被管理员取卡 log_1763710795914_e6bed17f=[2025-11-21 15\:39\:55] 取卡操作:卡槽54被管理员取卡 log_1763710800956_8dce7236=[2025-11-21 15\:40\:00] 取卡操作:卡槽55被管理员取卡 log_1763710805994_a2db9e8c=[2025-11-21 15\:40\:05] 取卡操作:卡槽56被管理员取卡 log_1763710811028_a8d51351=[2025-11-21 15\:40\:11] 取卡操作:卡槽57被管理员取卡 log_1763710816051_8e739946=[2025-11-21 15\:40\:16] 取卡操作:卡槽55被管理员取卡 log_1763710821079_97f443a0=[2025-11-21 15\:40\:21] 取卡操作:卡槽58被管理员取卡 log_1763710826129_6b6a9bef=[2025-11-21 15\:40\:26] 取卡操作:卡槽59被管理员取卡 log_1763710831168_7aa2fec2=[2025-11-21 15\:40\:31] 取卡操作:卡槽60被管理员取卡 log_1763710836208_cbc1493c=[2025-11-21 15\:40\:36] 取卡操作:卡槽55被管理员取卡 log_1763711168072_7a637b83=[2025-11-21 15\:46\:08] 取卡操作:卡槽1被管理员取卡 log_1763711168170_6eb3dca2=[2025-11-21 15\:46\:08] 取卡操作:卡槽2被管理员取卡 log_1763711168270_9dfe9ac0=[2025-11-21 15\:46\:08] 取卡操作:卡槽3被管理员取卡 log_1763711168370_0e757e2d=[2025-11-21 15\:46\:08] 取卡操作:卡槽4被管理员取卡 log_1763711168470_bb1dfc2f=[2025-11-21 15\:46\:08] 取卡操作:卡槽5被管理员取卡 log_1763711168570_6d6b4073=[2025-11-21 15\:46\:08] 取卡操作:卡槽6被管理员取卡 log_1763711168669_3cfb4ace=[2025-11-21 15\:46\:08] 取卡操作:卡槽7被管理员取卡 log_1763711168769_ba4e8f33=[2025-11-21 15\:46\:08] 取卡操作:卡槽8被管理员取卡 log_1763711168870_1c83d283=[2025-11-21 15\:46\:08] 取卡操作:卡槽9被管理员取卡 log_1763711168968_16b096e0=[2025-11-21 15\:46\:08] 取卡操作:卡槽10被管理员取卡 log_1763711169070_d8dd15fb=[2025-11-21 15\:46\:09] 取卡操作:卡槽11被管理员取卡 log_1763711169169_5918a8ad=[2025-11-21 15\:46\:09] 取卡操作:卡槽12被管理员取卡 log_1763711169269_6149934f=[2025-11-21 15\:46\:09] 取卡操作:卡槽13被管理员取卡 log_1763711169369_d661fd92=[2025-11-21 15\:46\:09] 取卡操作:卡槽14被管理员取卡 log_1763711169470_4f7a20e7=[2025-11-21 15\:46\:09] 取卡操作:卡槽15被管理员取卡 log_1763711169569_be376f54=[2025-11-21 15\:46\:09] 取卡操作:卡槽16被管理员取卡 log_1763711169721_f89247f7=[2025-11-21 15\:46\:09] 取卡操作:卡槽17被管理员取卡 log_1763711169820_361b5763=[2025-11-21 15\:46\:09] 取卡操作:卡槽18被管理员取卡 log_1763711169918_58ac9aff=[2025-11-21 15\:46\:09] 取卡操作:卡槽19被管理员取卡 log_1763711170019_05f162db=[2025-11-21 15\:46\:10] 取卡操作:卡槽20被管理员取卡 log_1763711170120_400f321f=[2025-11-21 15\:46\:10] 取卡操作:卡槽21被管理员取卡 log_1763711170220_f28795df=[2025-11-21 15\:46\:10] 取卡操作:卡槽22被管理员取卡 log_1763711170320_6c1ec7b4=[2025-11-21 15\:46\:10] 取卡操作:卡槽23被管理员取卡 log_1763711170420_123cd886=[2025-11-21 15\:46\:10] 取卡操作:卡槽24被管理员取卡 log_1763711170518_e12bca59=[2025-11-21 15\:46\:10] 取卡操作:卡槽25被管理员取卡 log_1763711170619_734131eb=[2025-11-21 15\:46\:10] 取卡操作:卡槽26被管理员取卡 log_1763711170720_993b63cb=[2025-11-21 15\:46\:10] 取卡操作:卡槽27被管理员取卡 log_1763711170820_d7232328=[2025-11-21 15\:46\:10] 取卡操作:卡槽28被管理员取卡 log_1763711170920_c6a6fbf9=[2025-11-21 15\:46\:10] 取卡操作:卡槽29被管理员取卡 log_1763711171020_410bcebc=[2025-11-21 15\:46\:11] 取卡操作:卡槽30被管理员取卡 log_1763711171170_e6790075=[2025-11-21 15\:46\:11] 取卡操作:卡槽31被管理员取卡 log_1763711171269_84e5843c=[2025-11-21 15\:46\:11] 取卡操作:卡槽32被管理员取卡 log_1763711171369_c3e6d9e3=[2025-11-21 15\:46\:11] 取卡操作:卡槽33被管理员取卡 log_1763711171469_2111fab1=[2025-11-21 15\:46\:11] 取卡操作:卡槽34被管理员取卡 log_1763711171569_fdb37f62=[2025-11-21 15\:46\:11] 取卡操作:卡槽35被管理员取卡 log_1763711171669_a00d8931=[2025-11-21 15\:46\:11] 取卡操作:卡槽36被管理员取卡 log_1763711171768_993fe6d8=[2025-11-21 15\:46\:11] 取卡操作:卡槽37被管理员取卡 log_1763711171869_aa296e9d=[2025-11-21 15\:46\:11] 取卡操作:卡槽38被管理员取卡 log_1763711171969_198e8166=[2025-11-21 15\:46\:11] 取卡操作:卡槽39被管理员取卡 log_1763711172069_47f47189=[2025-11-21 15\:46\:12] 取卡操作:卡槽40被管理员取卡 log_1763711172169_a0fe6996=[2025-11-21 15\:46\:12] 取卡操作:卡槽41被管理员取卡 log_1763711172270_f829f19c=[2025-11-21 15\:46\:12] 取卡操作:卡槽42被管理员取卡 log_1763711172368_544e99ef=[2025-11-21 15\:46\:12] 取卡操作:卡槽43被管理员取卡 log_1763711172469_35271c30=[2025-11-21 15\:46\:12] 取卡操作:卡槽44被管理员取卡 log_1763711172569_007a7812=[2025-11-21 15\:46\:12] 取卡操作:卡槽45被管理员取卡 log_1763711172669_a9d07106=[2025-11-21 15\:46\:12] 取卡操作:卡槽46被管理员取卡 log_1763711172819_70bacc6a=[2025-11-21 15\:46\:12] 取卡操作:卡槽47被管理员取卡 log_1763711172919_b0739863=[2025-11-21 15\:46\:12] 取卡操作:卡槽48被管理员取卡 log_1763711173020_443f36ed=[2025-11-21 15\:46\:13] 取卡操作:卡槽49被管理员取卡 log_1763711173120_ad2656d1=[2025-11-21 15\:46\:13] 取卡操作:卡槽50被管理员取卡 log_1763711173220_cb6c90a2=[2025-11-21 15\:46\:13] 取卡操作:卡槽51被管理员取卡 log_1763711173318_5b3b3197=[2025-11-21 15\:46\:13] 取卡操作:卡槽52被管理员取卡 log_1763711173419_cb609033=[2025-11-21 15\:46\:13] 取卡操作:卡槽53被管理员取卡 log_1763711173520_f3fbfaa3=[2025-11-21 15\:46\:13] 取卡操作:卡槽54被管理员取卡 log_1763711173620_a6626517=[2025-11-21 15\:46\:13] 取卡操作:卡槽55被管理员取卡 log_1763711173720_119445bc=[2025-11-21 15\:46\:13] 取卡操作:卡槽56被管理员取卡 log_1763711173820_34259d08=[2025-11-21 15\:46\:13] 取卡操作:卡槽57被管理员取卡 log_1763711173918_9b8dd187=[2025-11-21 15\:46\:13] 取卡操作:卡槽55被管理员取卡 log_1763711173919_78e51f34=[2025-11-21 15\:46\:13] 取卡操作:卡槽58被管理员取卡 log_1763711174020_de1b1d16=[2025-11-21 15\:46\:14] 取卡操作:卡槽59被管理员取卡 log_1763711174120_269ca2e6=[2025-11-21 15\:46\:14] 取卡操作:卡槽60被管理员取卡 log_1763711174220_660bae5f=[2025-11-21 15\:46\:14] 取卡操作:卡槽55被管理员取卡 log_1763711174519_b989bf73=[2025-11-21 15\:46\:14] 取卡操作:卡槽55被管理员取卡 log_1763711174820_64ba2235=[2025-11-21 15\:46\:14] 取卡操作:卡槽55被管理员取卡 log_1763711175119_4d03fcbf=[2025-11-21 15\:46\:15] 取卡操作:卡槽55被管理员取卡 log_1763711175420_d68f2c75=[2025-11-21 15\:46\:15] 取卡操作:卡槽55被管理员取卡 log_1763711175719_e0fd7858=[2025-11-21 15\:46\:15] 取卡操作:卡槽55被管理员取卡 log_1763711176020_c70ee0f2=[2025-11-21 15\:46\:16] 取卡操作:卡槽55被管理员取卡 log_1763711176319_38854f73=[2025-11-21 15\:46\:16] 取卡操作:卡槽55被管理员取卡 log_1763711176620_41d8db8a=[2025-11-21 15\:46\:16] 取卡操作:卡槽55被管理员取卡 log_1763711179015_2952f952=[2025-11-21 15\:46\:19] 管理员已将全部卡槽已经打开请取卡 log_1763713705096_9d5670de=[2025-11-21 16\:28\:25] DDCC0008F00C515AA55AA5027A81;type2控制打开12柜门 log_1763713705463_ebe6da20=[2025-11-21 16\:28\:25] 取卡操作:卡槽12被管理员取卡 log_1763715591886_1ac9cc5a=[2025-11-21 16\:59\:51] DDCC0008F013515AA55AA502BB6F;type2控制打开19柜门 log_1763715592224_8af42a4f=[2025-11-21 16\:59\:52] 取卡操作:卡槽19被管理员取卡 log_1763715735797_38b1a47b=[2025-11-21 17\:02\:15] DDCC0008F00D515AA55AA502BA91;type2控制打开13柜门 log_1763716227580_f95bc09a=[2025-11-21 17\:10\:27] DDCC0008F00C515AA55AA5027A81;type2控制打开12柜门 log_1763716227937_a73d3b5b=[2025-11-21 17\:10\:27] 取卡操作:卡槽12被管理员取卡 log_1763716377421_6577a6ec=[2025-11-21 17\:12\:57] 取卡操作:卡槽1被管理员取卡 log_1763716377517_f6fe46de=[2025-11-21 17\:12\:57] 取卡操作:卡槽2被管理员取卡 log_1763716377617_d4676872=[2025-11-21 17\:12\:57] 取卡操作:卡槽3被管理员取卡 log_1763716377717_f8ce2321=[2025-11-21 17\:12\:57] 取卡操作:卡槽4被管理员取卡 log_1763716377817_f2002ba4=[2025-11-21 17\:12\:57] 取卡操作:卡槽5被管理员取卡 log_1763716377916_112dc429=[2025-11-21 17\:12\:57] 取卡操作:卡槽6被管理员取卡 log_1763716378018_4f02bd40=[2025-11-21 17\:12\:58] 取卡操作:卡槽7被管理员取卡 log_1763716378116_91cb3159=[2025-11-21 17\:12\:58] 取卡操作:卡槽8被管理员取卡 log_1763716378217_d21090a4=[2025-11-21 17\:12\:58] 取卡操作:卡槽9被管理员取卡 log_1763716378316_eee62d13=[2025-11-21 17\:12\:58] 取卡操作:卡槽10被管理员取卡 log_1763716378416_49dfa52f=[2025-11-21 17\:12\:58] 取卡操作:卡槽11被管理员取卡 log_1763716378516_97fd0ebf=[2025-11-21 17\:12\:58] 取卡操作:卡槽12被管理员取卡 log_1763716378617_14298d78=[2025-11-21 17\:12\:58] 取卡操作:卡槽13被管理员取卡 log_1763716378716_89f7fe99=[2025-11-21 17\:12\:58] 取卡操作:卡槽14被管理员取卡 log_1763716378867_1ee85650=[2025-11-21 17\:12\:58] 取卡操作:卡槽15被管理员取卡 log_1763716378968_de0d5066=[2025-11-21 17\:12\:58] 取卡操作:卡槽16被管理员取卡 log_1763716379065_030b8980=[2025-11-21 17\:12\:59] 取卡操作:卡槽17被管理员取卡 log_1763716379166_2af275ec=[2025-11-21 17\:12\:59] 取卡操作:卡槽18被管理员取卡 log_1763716379267_b667a29e=[2025-11-21 17\:12\:59] 取卡操作:卡槽19被管理员取卡 log_1763716379367_2498a809=[2025-11-21 17\:12\:59] 取卡操作:卡槽20被管理员取卡 log_1763716379467_bfe1598a=[2025-11-21 17\:12\:59] 取卡操作:卡槽21被管理员取卡 log_1763716379567_cb9eb62b=[2025-11-21 17\:12\:59] 取卡操作:卡槽22被管理员取卡 log_1763716379666_688ebc2f=[2025-11-21 17\:12\:59] 取卡操作:卡槽23被管理员取卡 log_1763716379766_0087530c=[2025-11-21 17\:12\:59] 取卡操作:卡槽24被管理员取卡 log_1763716379867_4611e338=[2025-11-21 17\:12\:59] 取卡操作:卡槽25被管理员取卡 log_1763716379967_fdaa10ff=[2025-11-21 17\:12\:59] 取卡操作:卡槽26被管理员取卡 log_1763716380067_7066ebe8=[2025-11-21 17\:13\:00] 取卡操作:卡槽27被管理员取卡 log_1763716380167_daa20dbf=[2025-11-21 17\:13\:00] 取卡操作:卡槽28被管理员取卡 log_1763716380266_a7c6e4f7=[2025-11-21 17\:13\:00] 取卡操作:卡槽29被管理员取卡 log_1763716380366_1dc8dacf=[2025-11-21 17\:13\:00] 取卡操作:卡槽30被管理员取卡 log_1763716380516_d28c278d=[2025-11-21 17\:13\:00] 取卡操作:卡槽31被管理员取卡 log_1763716380616_8e7dc215=[2025-11-21 17\:13\:00] 取卡操作:卡槽32被管理员取卡 log_1763716380716_2d57a4ef=[2025-11-21 17\:13\:00] 取卡操作:卡槽33被管理员取卡 log_1763716380817_27f8849c=[2025-11-21 17\:13\:00] 取卡操作:卡槽34被管理员取卡 log_1763716380915_556a565a=[2025-11-21 17\:13\:00] 取卡操作:卡槽35被管理员取卡 log_1763716381016_a66e5689=[2025-11-21 17\:13\:01] 取卡操作:卡槽36被管理员取卡 log_1763716381116_2f621f7e=[2025-11-21 17\:13\:01] 取卡操作:卡槽37被管理员取卡 log_1763716381216_8ee638c7=[2025-11-21 17\:13\:01] 取卡操作:卡槽38被管理员取卡 log_1763716381316_4a494195=[2025-11-21 17\:13\:01] 取卡操作:卡槽39被管理员取卡 log_1763716381417_d2e4fce3=[2025-11-21 17\:13\:01] 取卡操作:卡槽40被管理员取卡 log_1763716381516_ad2c841b=[2025-11-21 17\:13\:01] 取卡操作:卡槽41被管理员取卡 log_1763716381616_f769b6ee=[2025-11-21 17\:13\:01] 取卡操作:卡槽42被管理员取卡 log_1763716381716_749a04bd=[2025-11-21 17\:13\:01] 取卡操作:卡槽43被管理员取卡 log_1763716381816_36768fce=[2025-11-21 17\:13\:01] 取卡操作:卡槽44被管理员取卡 log_1763716381916_8dfccd10=[2025-11-21 17\:13\:01] 取卡操作:卡槽45被管理员取卡 log_1763716382066_05896cc1=[2025-11-21 17\:13\:02] 取卡操作:卡槽46被管理员取卡 log_1763716382167_4f94fd40=[2025-11-21 17\:13\:02] 取卡操作:卡槽47被管理员取卡 log_1763716382267_e13e3734=[2025-11-21 17\:13\:02] 取卡操作:卡槽48被管理员取卡 log_1763716382367_b5591084=[2025-11-21 17\:13\:02] 取卡操作:卡槽49被管理员取卡 log_1763716382465_8b6a0f92=[2025-11-21 17\:13\:02] 取卡操作:卡槽50被管理员取卡 log_1763716382566_039d11f4=[2025-11-21 17\:13\:02] 取卡操作:卡槽51被管理员取卡 log_1763716382667_97480314=[2025-11-21 17\:13\:02] 取卡操作:卡槽52被管理员取卡 log_1763716382767_1ce157e6=[2025-11-21 17\:13\:02] 取卡操作:卡槽53被管理员取卡 log_1763716382867_2128e536=[2025-11-21 17\:13\:02] 取卡操作:卡槽54被管理员取卡 log_1763716382967_f3041239=[2025-11-21 17\:13\:02] 取卡操作:卡槽55被管理员取卡 log_1763716383066_ea1f332b=[2025-11-21 17\:13\:03] 取卡操作:卡槽56被管理员取卡 log_1763716383166_9d894f87=[2025-11-21 17\:13\:03] 取卡操作:卡槽57被管理员取卡 log_1763716383267_b0a3c9a1=[2025-11-21 17\:13\:03] 取卡操作:卡槽58被管理员取卡 log_1763716383368_65a77f09=[2025-11-21 17\:13\:03] 取卡操作:卡槽59被管理员取卡 log_1763716383468_1d41c7bb=[2025-11-21 17\:13\:03] 取卡操作:卡槽60被管理员取卡 log_1763716384559_af7c9cc7=[2025-11-21 17\:13\:04] 管理员已将全部卡槽已经打开请取卡 #\u64CD\u4F5C\u65E5\u5FD7\u8BB0\u5F55 - \u6700\u540E\u66F4\u65B0: Fri Nov 21 17:44:41 CST 2025 #Fri Nov 21 17:44:41 CST 2025 log_1763718093181_61c0dfbe=[2025-11-21 17\:41\:33] 取卡操作:卡槽13被管理员取卡 log_1763718093533_c3563f25=[2025-11-21 17\:41\:33] 取卡操作:卡槽13被管理员取卡 log_1763718147310_e84a6b5b=[2025-11-21 17\:42\:27] 取卡操作:卡槽22被管理员取卡 log_1763718150490_e2f94107=[2025-11-21 17\:42\:30] 取卡操作:卡槽23被管理员取卡 log_1763718150843_c9147690=[2025-11-21 17\:42\:30] 取卡操作:卡槽23被管理员取卡 log_1763718198841_27d9aa77=[2025-11-21 17\:43\:18] 取卡操作:卡槽12被管理员取卡 log_1763718199155_4cd5e39f=[2025-11-21 17\:43\:19] 取卡操作:卡槽12被管理员取卡 log_1763718207706_07760e2f=[2025-11-21 17\:43\:27] DDCC0008F003515AA55AA5027A7E;type2控制打开3柜门 log_1763718208053_ee80022a=[2025-11-21 17\:43\:28] 3号卡槽取卡失败 log_1763718208759_e8be3ec0=[2025-11-21 17\:43\:28] DDCC0008F003515AA55AA5027A7E;type2控制打开3柜门 log_1763718209104_247397ce=[2025-11-21 17\:43\:29] 取卡操作:卡槽3被管理员取卡 log_1763718275945_e2a4d769=[2025-11-21 17\:44\:35] DDCC0008F012515AA55AA5027B7F;type2控制打开18柜门 log_1763718276293_034826af=[2025-11-21 17\:44\:36] 取卡操作:卡槽18被管理员取卡 log_1763718276666_18777eee=[2025-11-21 17\:44\:36] DDCC0008F017515AA55AA5027B2A;type2控制打开23柜门 log_1763718276992_c9ad983a=[2025-11-21 17\:44\:36] 取卡操作:卡槽23被管理员取卡 log_1763718277268_15912a52=[2025-11-21 17\:44\:37] DDCC0008F01C515AA55AA502BB90;type2控制打开28柜门 log_1763718277593_d9b897ba=[2025-11-21 17\:44\:37] 取卡操作:卡槽28被管理员取卡 log_1763718277892_72d570bd=[2025-11-21 17\:44\:37] DDCC0008F018515AA55AA5027BD5;type2控制打开24柜门 log_1763718278242_75327d86=[2025-11-21 17\:44\:38] 取卡操作:卡槽24被管理员取卡 log_1763718278782_a91dddda=[2025-11-21 17\:44\:38] DDCC0008F00E515AA55AA502BAA2;type2控制打开14柜门 log_1763718279143_4e4cb89a=[2025-11-21 17\:44\:39] 取卡操作:卡槽14被管理员取卡 log_1763718279202_9c58a3b9=[2025-11-21 17\:44\:39] DDCC0008F013515AA55AA502BB6F;type2控制打开19柜门 log_1763718279543_9e40ceff=[2025-11-21 17\:44\:39] 取卡操作:卡槽19被管理员取卡 log_1763718279709_4483c6c4=[2025-11-21 17\:44\:39] DDCC0008F01D515AA55AA5027B80;type2控制打开29柜门 log_1763718280043_06750db2=[2025-11-21 17\:44\:40] 取卡操作:卡槽29被管理员取卡 log_1763718280658_b6288ce6=[2025-11-21 17\:44\:40] DDCC0008F00F515AA55AA5027AB2;type2控制打开15柜门 log_1763718280993_f6f218cc=[2025-11-21 17\:44\:40] 取卡操作:卡槽15被管理员取卡 log_1763718281030_2d1edd96=[2025-11-21 17\:44\:41] DDCC0008F014515AA55AA5027B19;type2控制打开20柜门 log_1763718281392_c8b2ee8c=[2025-11-21 17\:44\:41] 取卡操作:卡槽20被管理员取卡 log_1763718281404_56d7aa71=[2025-11-21 17\:44\:41] DDCC0008F019515AA55AA502BBC5;type2控制打开25柜门 log_1763718281743_12a79e45=[2025-11-21 17\:44\:41] 取卡操作:卡槽25被管理员取卡 src/chuankou/Sendmsg.java
@@ -1,6 +1,8 @@ package chuankou; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.SwingWorker; @@ -14,35 +16,55 @@ /** * 串口消息发送工具类 * 提供高性能的串口消息发送功能,适合高频调用 * 优化内存使用,避免长时间运行内存泄漏 */ public class Sendmsg { // 静态串口服务实例 private static volatile SerialPortService serialService = null; private static volatile boolean isPortOpen = false; private static final AtomicBoolean isPortOpen = new AtomicBoolean(false); // 改为非final,支持动态控制 private static boolean DEBUG_MODE = false; private static volatile boolean DEBUG_MODE = false; // 日期格式化 private static final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss.SSS"); // 使用ThreadLocal保证SimpleDateFormat线程安全 private static final ThreadLocal<SimpleDateFormat> TIME_FORMATTER = ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss.SSS")); // 缓存字符串构建器,减少对象创建 private static final ThreadLocal<StringBuilder> STRING_BUILDER_CACHE = ThreadLocal.withInitial(() -> new StringBuilder(128)); // 记录活跃的SwingWorker,便于管理 private static final ConcurrentHashMap<String, SwingWorker<?, ?>> ACTIVE_WORKERS = new ConcurrentHashMap<>(); /**发卡服务器控制打开某个柜门调用指令 * @param int slotId柜门编号1-60 * @param int type 1是服务器发卡,2是管理员发卡*/ public static boolean opendoorzhiling(int slotId,int type) { lunxun.setSendChaxunzhiling(false);//暂停查询指令 // 调用OpenDoor生成开门指令 String command = OpenDoor.openOneDoor(slotId, type); boolean sendResult = Sendmsg.sendMessage(command); String mes=command+";type"+type+"控制打开"+slotId+"柜门"; Charulog.logOperation(mes); if (lunxun.DEBUG_ENABLED) { SystemDebugDialog.appendAsciiData(mes); lunxun.setSendChaxunzhiling(false);//暂停查询指令 try { // 调用OpenDoor生成开门指令 String command = OpenDoor.openOneDoor(slotId, type); boolean sendResult = Sendmsg.sendMessage(command); StringBuilder mesBuilder = STRING_BUILDER_CACHE.get(); mesBuilder.setLength(0); // 清空重用 mesBuilder.append(command).append(";type").append(type).append("控制打开").append(slotId).append("柜门"); String mes = mesBuilder.toString(); Charulog.logOperation(mes); if (lunxun.DEBUG_ENABLED) { SystemDebugDialog.appendAsciiData(mes); } return sendResult; } finally { // 确保恢复查询指令 lunxun.setSendChaxunzhiling(true); } lunxun.setSendChaxunzhiling(true);//开始查询指令 return sendResult; } /** @@ -50,13 +72,16 @@ * @param type 操作类型:1-服务器发卡,2-管理员发卡 */ public static void openAllSlots(int type) { lunxun.setSendChaxunzhiling(false);//暂停查询指令 lunxun.setSendChaxunzhiling(false);//暂停查询指令 String workerKey = "openAllSlots_" + System.currentTimeMillis(); // 使用SwingWorker在后台执行,避免阻塞UI SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { @Override protected Void doInBackground() throws Exception { // 遍历所有卡槽(1-60) for (int slotId = 1; slotId <= 60; slotId++) { for (int slotId = 1; slotId <= 60 && !isCancelled(); slotId++) { try { // 生成开门指令 String command = OpenDoor.openOneDoor(slotId, type); @@ -68,12 +93,15 @@ Errlog.logOperation("发送指令到卡槽 " + slotId + " 失败"); } // 间隔100ms // 间隔100ms,但检查是否被取消 Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; // 被中断时退出循环 } catch (Exception e) { Errlog.logOperation("处理卡槽 " + slotId + " 时发生错误: " + e.getMessage()); e.printStackTrace(); // 继续处理下一个卡槽,不中断循环 } } return null; @@ -81,22 +109,48 @@ @Override protected void done() { // 可选:完成后可以添加回调处理 System.out.println("全部卡槽开门指令发送完成"); String types="管理员"; if(type==1) { types="服务器指令"; try { // 清理worker引用 ACTIVE_WORKERS.remove(workerKey); // 可选:完成后可以添加回调处理 if (!isCancelled()) { StringBuilder messageBuilder = STRING_BUILDER_CACHE.get(); messageBuilder.setLength(0); String types = "管理员"; if(type == 1) { types = "服务器指令"; } messageBuilder.append(types).append("已将全部卡槽已经打开请取卡"); String message = messageBuilder.toString(); Dingshidialog.showTimedDialog(null, 5, message); Charulog.logOperation(message); } } finally { // 确保恢复查询指令 lunxun.setSendChaxunzhiling(true); } String message=types+"已将全部卡槽已经打开请取卡"; Dingshidialog.showTimedDialog(null,5,message); Charulog.logOperation(message); } }; // 记录worker便于管理 ACTIVE_WORKERS.put(workerKey, worker); worker.execute(); lunxun.setSendChaxunzhiling(true);//开始查询指令 } /** * 取消所有正在执行的任务 */ public static void cancelAllTasks() { ACTIVE_WORKERS.forEach((key, worker) -> { if (!worker.isDone()) { worker.cancel(true); } }); ACTIVE_WORKERS.clear(); } /** * 设置串口服务实例 @@ -105,7 +159,7 @@ */ public static void setSerialService(SerialPortService service, boolean open) { serialService = service; isPortOpen = open; isPortOpen.set(open); } /** @@ -119,7 +173,7 @@ * 发送消息到串口(带重试机制) */ public static boolean sendMessage(String message) { if (!isPortOpen || serialService == null) { if (!isPortOpen.get() || serialService == null) { Errlog.logOperation("[" + getCurrentTime() + "] 串口未打开,无法发送数据"); return false; } @@ -159,17 +213,21 @@ break; } } else { Errlog.logOperation("[" + getCurrentTime() + "] 串口发送失败,指令: " + text.toUpperCase()); Errlog.logOperation("[" + getCurrentTime() + "] 串口状态 - 打开: " + isPortOpen + ", 服务: " + (serialService != null)); if (serialService != null) { Errlog.logOperation("[" + getCurrentTime() + "] 串口服务状态 - 是否打开: " + serialService.isOpen()); if (DEBUG_MODE) { Errlog.logOperation("[" + getCurrentTime() + "] 串口发送失败,指令: " + text.toUpperCase()); Errlog.logOperation("[" + getCurrentTime() + "] 串口状态 - 打开: " + isPortOpen.get() + ", 服务: " + (serialService != null)); if (serialService != null) { Errlog.logOperation("[" + getCurrentTime() + "] 串口服务状态 - 是否打开: " + serialService.isOpen()); } } return false; } } } catch (Exception e) { Errlog.logOperation("[" + getCurrentTime() + "] 发送异常,指令: " + text.toUpperCase()); e.printStackTrace(); if (DEBUG_MODE) { e.printStackTrace(); } return false; } } @@ -182,7 +240,7 @@ * @return 串口打开状态 */ public static boolean isPortOpen() { boolean open = isPortOpen && serialService != null; boolean open = isPortOpen.get() && serialService != null; if (!open && DEBUG_MODE) { Errlog.logOperation("[" + getCurrentTime() + "] 串口状态检查: 未打开"); } @@ -229,7 +287,8 @@ return ""; } StringBuilder sb = new StringBuilder(); StringBuilder sb = STRING_BUILDER_CACHE.get(); sb.setLength(0); for (byte b : bytes) { sb.append(String.format("%02x", b)); } @@ -241,7 +300,7 @@ * @return 时间字符串 */ private static String getCurrentTime() { return timeFormat.format(new Date()); return TIME_FORMATTER.get().format(new Date()); } /** @@ -267,4 +326,26 @@ DEBUG_MODE = debug; System.out.println("[" + getCurrentTime() + "] Sendmsg调试模式: " + (debug ? "启用" : "禁用")); } /** * 清理资源,防止内存泄漏 */ public static void cleanup() { cancelAllTasks(); // 清理ThreadLocal资源 TIME_FORMATTER.remove(); STRING_BUILDER_CACHE.remove(); if (DEBUG_MODE) { System.out.println("[" + getCurrentTime() + "] Sendmsg资源清理完成"); } } /** * 获取活跃任务数量 */ public static int getActiveTaskCount() { return ACTIVE_WORKERS.size(); } } src/chuankou/SerialDataReceiver.java
@@ -6,21 +6,26 @@ public class SerialDataReceiver { private static final int BUFFER_SIZE = 1024; private static byte[] staticDataBuffer = new byte[BUFFER_SIZE]; private static int staticBufferPosition = 0; private static final int MIN_PACKET_LENGTH = 9; private static final byte[] START_MARKER = {(byte) 0xDD, (byte) 0xCC}; // 使用非静态成员避免多线程环境下的竞争条件 private byte[] dataBuffer = new byte[BUFFER_SIZE]; private int bufferPosition = 0; private final List<byte[]> reusablePackets = new ArrayList<>(); /** * 静态方法:接收串口原始数据并解析完整数据包 * 实例方法:接收串口原始数据并解析完整数据包 * @param rawData 原始数据 * @param debugEnabled 是否启用调试 * @param maxRawDataPrintLength 最大打印长度 * @return 解析出的完整数据包列表,如果没有完整包则返回空列表 */ public static List<byte[]> receiveData(byte[] rawData, boolean debugEnabled, int maxRawDataPrintLength) { List<byte[]> completePackets = new ArrayList<>(); public List<byte[]> receiveData(byte[] rawData, boolean debugEnabled, int maxRawDataPrintLength) { reusablePackets.clear(); if (rawData == null || rawData.length == 0) { return completePackets; return reusablePackets; } // 打印原始接收数据(调试用) @@ -28,88 +33,114 @@ printRawData("收到串口原始数据", rawData, maxRawDataPrintLength); } // 将数据添加到缓冲区 if (staticBufferPosition + rawData.length > staticDataBuffer.length) { // 检查缓冲区容量,动态处理 if (!ensureBufferCapacity(rawData.length)) { // 缓冲区不足时,清理并重新开始 System.arraycopy(staticDataBuffer, staticBufferPosition - rawData.length, staticDataBuffer, 0, rawData.length); staticBufferPosition = rawData.length; } else { System.arraycopy(rawData, 0, staticDataBuffer, staticBufferPosition, rawData.length); staticBufferPosition += rawData.length; if (debugEnabled) { System.out.println("缓冲区不足,清空缓冲区重新开始"); } bufferPosition = 0; } // 处理缓冲区中的数据并收集完整包 processBuffer(completePackets, debugEnabled); // 将数据添加到缓冲区 System.arraycopy(rawData, 0, dataBuffer, bufferPosition, rawData.length); bufferPosition += rawData.length; return completePackets; // 处理缓冲区中的数据并收集完整包 processBuffer(reusablePackets, debugEnabled); return new ArrayList<>(reusablePackets); } /** * 确保缓冲区有足够容量,如不够则尝试压缩 */ private boolean ensureBufferCapacity(int required) { if (bufferPosition + required <= dataBuffer.length) { return true; } // 尝试通过压缩缓冲区来腾出空间 int startIndex = findStartMarker(); if (startIndex > 0) { compactBuffer(startIndex); return bufferPosition + required <= dataBuffer.length; } return false; } /** * 处理缓冲区中的数据,解析完整数据包 */ private static void processBuffer(List<byte[]> completePackets, boolean debugEnabled) { final int MIN_PACKET_LENGTH = 9; final byte[] START_MARKER = {(byte) 0xDD, (byte) 0xCC}; while (staticBufferPosition >= MIN_PACKET_LENGTH) { private void processBuffer(List<byte[]> completePackets, boolean debugEnabled) { while (bufferPosition >= MIN_PACKET_LENGTH) { // 查找起始标记 int startIndex = findStartMarker(START_MARKER); int startIndex = findStartMarker(); if (startIndex == -1) { // 没有找到起始标记,清空无效数据 if (debugEnabled) { //System.out.println("未找到起始标记,清空缓冲区"); System.out.println("未找到起始标记,清空缓冲区"); } staticBufferPosition = 0; bufferPosition = 0; return; } // 检查是否有足够的数据读取数据长度 if (startIndex + 4 > staticBufferPosition) { if (startIndex + 4 > bufferPosition) { // 数据不足,等待更多数据 compactBuffer(startIndex); return; } // 读取数据长度 (大端序) int dataLength = ((staticDataBuffer[startIndex + 2] & 0xFF) << 8) | (staticDataBuffer[startIndex + 3] & 0xFF); int dataLength = ((dataBuffer[startIndex + 2] & 0xFF) << 8) | (dataBuffer[startIndex + 3] & 0xFF); int totalPacketLength = 2 + 2 + dataLength + 2; // 起始标记2 + 数据长度2 + 数据内容 + CRC2 // 检查数据长度有效性 if (dataLength < 0 || totalPacketLength > BUFFER_SIZE) { if (debugEnabled) { System.out.println("无效数据长度: " + dataLength + ", 跳过起始字节"); } // 跳过错误的起始标记,继续查找 compactBuffer(startIndex + 1); continue; } // 检查是否收到完整数据包 if (startIndex + totalPacketLength > staticBufferPosition) { if (startIndex + totalPacketLength > bufferPosition) { // 数据包不完整,等待更多数据 compactBuffer(startIndex); return; } // 提取完整数据包 byte[] packet = new byte[totalPacketLength]; System.arraycopy(staticDataBuffer, startIndex, packet, 0, totalPacketLength); byte[] packet = Arrays.copyOfRange(dataBuffer, startIndex, startIndex + totalPacketLength); if (debugEnabled) { //System.out.println("解析到完整数据包: " + bytesToHex(packet)); System.out.println("解析到完整数据包: " + bytesToHex(packet)); } // 添加到返回列表 completePackets.add(packet); // 移动缓冲区位置 int remaining = staticBufferPosition - (startIndex + totalPacketLength); int remaining = bufferPosition - (startIndex + totalPacketLength); if (remaining > 0) { System.arraycopy(staticDataBuffer, startIndex + totalPacketLength, staticDataBuffer, 0, remaining); System.arraycopy(dataBuffer, startIndex + totalPacketLength, dataBuffer, 0, remaining); } staticBufferPosition = remaining; bufferPosition = remaining; } } /** * 查找起始标记位置 */ private static int findStartMarker(byte[] startMarker) { for (int i = 0; i <= staticBufferPosition - startMarker.length; i++) { if (staticDataBuffer[i] == startMarker[0] && staticDataBuffer[i + 1] == startMarker[1]) { private int findStartMarker() { for (int i = 0; i <= bufferPosition - START_MARKER.length; i++) { if (dataBuffer[i] == START_MARKER[0] && dataBuffer[i + 1] == START_MARKER[1]) { return i; } } @@ -119,20 +150,20 @@ /** * 压缩缓冲区,将有效数据移到开头 */ private static void compactBuffer(int startIndex) { if (startIndex > 0) { System.arraycopy(staticDataBuffer, startIndex, staticDataBuffer, 0, staticBufferPosition - startIndex); staticBufferPosition -= startIndex; private void compactBuffer(int startIndex) { if (startIndex > 0 && startIndex < bufferPosition) { System.arraycopy(dataBuffer, startIndex, dataBuffer, 0, bufferPosition - startIndex); bufferPosition -= startIndex; } } /** * 打印原始数据(调试用) */ private static void printRawData(String prefix, byte[] data, int maxPrintLength) { private void printRawData(String prefix, byte[] data, int maxPrintLength) { if (data == null || data.length == 0) { //System.out.println(prefix + ": 空数据"); System.out.println(prefix + ": 空数据"); return; } @@ -148,13 +179,13 @@ sb.append("... [截断,总长度: ").append(data.length).append("]"); } //System.out.println(sb.toString()); System.out.println(sb.toString()); } /** * 工具方法:字节数组转十六进制字符串 */ private static String bytesToHex(byte[] bytes) { private String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X ", b)); @@ -165,16 +196,23 @@ /** * 清空缓冲区(避免内存泄漏) */ public static void clearBuffer() { staticBufferPosition = 0; public void clearBuffer() { bufferPosition = 0; // 可选:清空缓冲区内容 Arrays.fill(staticDataBuffer, (byte) 0); Arrays.fill(dataBuffer, (byte) 0); } /** * 获取当前缓冲区状态 */ public static int getBufferStatus() { return staticBufferPosition; public int getBufferStatus() { return bufferPosition; } /** * 获取缓冲区容量 */ public int getBufferCapacity() { return dataBuffer.length; } } src/chushihua/lunxun.java
@@ -7,6 +7,7 @@ import publicway.QueryData; import xitongshezhi.SystemDebugDialog; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -16,6 +17,7 @@ * 用于定时向所有卡槽发送查询指令 * 支持暂停和恢复功能,检查串口连接状态 * 新增:不同卡槽状态使用不同查询频率 * 优化:内存管理和长时间运行稳定性 */ public class lunxun { private static volatile boolean isRunning = false; @@ -24,14 +26,6 @@ private static Thread pollingThread; private static int pollingInterval = 100; // 默认轮询间隔 public static boolean sendChaxunzhiling=true;//是否向串口发送查询指令 public static boolean isSendChaxunzhiling() { return sendChaxunzhiling; } public static void setSendChaxunzhiling(boolean sendChaxunzhiling) { lunxun.sendChaxunzhiling = sendChaxunzhiling; } // 卡槽相关常量 private static final int MIN_SLOT = 1; @@ -44,6 +38,15 @@ // 性能优化:查询指令缓存 private static final Map<Integer, String> queryCommandCache = new ConcurrentHashMap<>(); // 内存优化:缓存大小限制和清理机制 private static final int MAX_CACHE_SIZE = 100; private static final long CACHE_CLEANUP_INTERVAL = 60000; // 1分钟清理一次 private static long lastCleanupTime = 0; // 错误日志限流机制 private static final Map<String, Long> lastErrorLogTime = new ConcurrentHashMap<>(); private static final long ERROR_LOG_INTERVAL = 5000; // 相同错误5秒内只记录一次 // 调试模式控制 public static boolean DEBUG_ENABLED = false; @@ -52,6 +55,14 @@ private static final int NO_CARD_QUERY_INTERVAL = 100; // 无卡卡槽查询间隔:100ms private static final int HAS_CARD_QUERY_INTERVAL = 10000; // 有卡卡槽查询间隔:10秒 private static final Map<Integer, Long> lastQueryTimeMap = new ConcurrentHashMap<>(); // 记录每个卡槽的最后查询时间 public static boolean isSendChaxunzhiling() { return sendChaxunzhiling; } public static void setSendChaxunzhiling(boolean sendChaxunzhiling) { lunxun.sendChaxunzhiling = sendChaxunzhiling; } /** * 检查串口连接状态 - 优化版本,添加重试机制 @@ -76,11 +87,11 @@ } serialConnected = true; } else { Errlog.logOperation("串口连接失败 - 串口未打开"); logErrorWithRateLimit("serial_connection_failed", "串口连接失败 - 串口未打开"); serialConnected = false; } } catch (Exception e) { Errlog.logOperation("串口连接检查异常: " + e.getMessage()); logErrorWithRateLimit("serial_connection_exception", "串口连接检查异常: " + e.getMessage()); serialConnected = false; } @@ -117,9 +128,12 @@ // 启动前严格检查串口连接 if (!checkSerialConnectionWithRetry()) { Errlog.logOperation("串口未连接,无法启动轮询查询"); logErrorWithRateLimit("start_polling_serial_failed", "串口未连接,无法启动轮询查询"); return false; } // 启动前先清理一次内存 performCleanup(); // 从配置中获取轮询间隔 loadPollingIntervalFromConfig(); @@ -137,7 +151,7 @@ pollingThread.start(); return true; } catch (Exception e) { Errlog.logOperation("启动轮询查询线程时发生异常: " + e.getMessage()); logErrorWithRateLimit("start_polling_thread_exception", "启动轮询查询线程时发生异常: " + e.getMessage()); isRunning = false; shouldStop.set(true); return false; @@ -174,15 +188,15 @@ pollingThread.join(3000); // 等待3秒 // 检查线程是否还在运行 if (pollingThread.isAlive()) { Errlog.logOperation("轮询线程未在3秒内停止,标记为守护线程并忽略"); logErrorWithRateLimit("polling_thread_stop_timeout", "轮询线程未在3秒内停止,标记为守护线程并忽略"); // 不强制停止,而是确保它是守护线程 pollingThread.setDaemon(true); } } catch (InterruptedException e) { Errlog.logOperation("停止轮询查询时被中断: " + e.getMessage()); logErrorWithRateLimit("stop_polling_interrupted", "停止轮询查询时被中断: " + e.getMessage()); Thread.currentThread().interrupt(); } catch (Exception e) { Errlog.logOperation("停止轮询线程时发生异常: " + e.getMessage()); logErrorWithRateLimit("stop_polling_exception", "停止轮询线程时发生异常: " + e.getMessage()); } finally { pollingThread = null; } @@ -234,7 +248,7 @@ // 恢复前检查串口连接 if (!checkSerialConnectionWithRetry()) { Errlog.logOperation("串口未连接,无法恢复轮询查询"); logErrorWithRateLimit("resume_polling_serial_failed", "串口未连接,无法恢复轮询查询"); return false; } @@ -276,7 +290,7 @@ */ public static void setPollingInterval(int interval) { if (interval < 10) { Errlog.logOperation("轮询间隔不能小于10ms"); logErrorWithRateLimit("polling_interval_too_small", "轮询间隔不能小于10ms"); return; } @@ -328,7 +342,7 @@ //System.out.println("配置系统未初始化,使用默认轮询间隔: " + pollingInterval + "ms"); } } catch (Exception e) { Errlog.logOperation("加载轮询间隔配置失败: " + e.getMessage()); logErrorWithRateLimit("load_polling_interval_failed", "加载轮询间隔配置失败: " + e.getMessage()); //System.out.println("使用默认轮询间隔: " + pollingInterval + "ms"); } } @@ -351,12 +365,13 @@ /** * 轮询任务内部类 - 优化版本 * 支持不同状态卡槽的不同查询频率 * 优化:内存管理和重用对象 */ private static class PollingTask implements Runnable { private int currentIndex = 0; // 当前索引,用于遍历slotArray private int consecutiveFailures = 0; // 连续失败次数 private static final int MAX_CONSECUTIVE_FAILURES = 5; // 最大连续失败次数 private final StringBuilder debugBuilder = new StringBuilder(100); // 重用 StringBuilder @Override public void run() { @@ -378,15 +393,20 @@ // 定期检查串口连接状态(每10次循环检查一次) if (currentIndex % 10 == 0 && !checkSerialConnectionWithRetry()) { Errlog.logOperation("串口连接断开,暂停轮询"); logErrorWithRateLimit("serial_disconnected", "串口连接断开,暂停轮询"); pausePolling(); continue; } // 定期清理缓存(每100次循环清理一次) if (currentIndex % 100 == 0) { cleanupOldCache(); } // 获取卡槽数组 Fkj[] slotArray = SlotManager.getSlotArray(); if (slotArray == null || slotArray.length == 0) { Errlog.logOperation("卡槽数组未初始化"); logErrorWithRateLimit("slot_array_not_initialized", "卡槽数组未初始化"); Thread.sleep(pollingInterval); continue; } @@ -427,18 +447,18 @@ } else { status = "无卡"; } if (DEBUG_ENABLED) { StringBuilder debugMsg = new StringBuilder(50); debugMsg.append("Slot ").append(slotNumber) .append(" (").append(status).append(") 查询成功,间隔: ") .append(queryInterval).append("ms\n"); SystemDebugDialog.appendAsciiData(debugMsg.toString()); } // 使用重用的 StringBuilder 构建调试信息 debugBuilder.setLength(0); debugBuilder.append("Slot ").append(slotNumber) .append(" (").append(status).append(") 查询成功,间隔: ") .append(queryInterval).append("ms\n"); SystemDebugDialog.appendAsciiData(debugBuilder.toString()); } } else { consecutiveFailures++; if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) { Errlog.logOperation("lunxun连续失败次数过多,暂停轮询"); logErrorWithRateLimit("consecutive_failures", "lunxun连续失败次数过多,暂停轮询"); pausePolling(); break; } @@ -460,7 +480,7 @@ Thread.currentThread().interrupt(); break; } catch (Exception e) { Errlog.logOperation("轮询查询过程中发生异常: " + e.getMessage()); logErrorWithRateLimit("polling_exception", "轮询查询过程中发生异常: " + e.getMessage()); consecutiveFailures++; // 发生异常时等待一段时间再继续 @@ -508,12 +528,12 @@ return false; } } else { Errlog.logOperation("生成的查询指令为空,卡槽: " + slotNumber); logErrorWithRateLimit("empty_query_command", "生成的查询指令为空,卡槽: " + slotNumber); return false; } } catch (Exception e) { Errlog.logOperation("发送查询指令到卡槽 " + slotNumber + " 时发生异常: " + e.getMessage()); logErrorWithRateLimit("send_query_exception", "发送查询指令到卡槽 " + slotNumber + " 时发生异常: " + e.getMessage()); // 发生异常时更新串口连接状态 serialConnected = false; return false; @@ -528,13 +548,13 @@ */ public static boolean sendImmediateQuery(int slotNumber) { if (slotNumber < MIN_SLOT || slotNumber > MAX_SLOT) { Errlog.logOperation("卡槽编号必须在" + MIN_SLOT + "-" + MAX_SLOT + "之间"); logErrorWithRateLimit("invalid_slot_number", "卡槽编号必须在" + MIN_SLOT + "-" + MAX_SLOT + "之间"); return false; } // 检查串口连接 if (!checkSerialConnectionWithRetry()) { Errlog.logOperation("串口未连接,无法发送查询指令"); logErrorWithRateLimit("immediate_query_serial_failed", "串口未连接,无法发送查询指令"); return false; } @@ -555,16 +575,16 @@ } return true; } else { Errlog.logOperation("立即查询失败 - 发送指令到卡槽 " + slotNumber + " 失败"); logErrorWithRateLimit("immediate_query_send_failed", "立即查询失败 - 发送指令到卡槽 " + slotNumber + " 失败"); return false; } } else { Errlog.logOperation("立即查询失败 - 生成的查询指令为空,卡槽: " + slotNumber); logErrorWithRateLimit("immediate_query_empty_command", "立即查询失败 - 生成的查询指令为空,卡槽: " + slotNumber); return false; } } catch (Exception e) { Errlog.logOperation("立即查询卡槽 " + slotNumber + " 时发生异常: " + e.getMessage()); logErrorWithRateLimit("immediate_query_exception", "立即查询卡槽 " + slotNumber + " 时发生异常: " + e.getMessage()); return false; } } @@ -576,7 +596,7 @@ public static int sendImmediateQueryToAll() { // 检查串口连接 if (!checkSerialConnectionWithRetry()) { Errlog.logOperation("串口未连接,无法发送批量查询指令"); logErrorWithRateLimit("batch_query_serial_failed", "串口未连接,无法发送批量查询指令"); return 0; } @@ -629,7 +649,7 @@ if (connected) { // //System.out.println("串口连接状态已设置为: 已连接"); } else { Errlog.logOperation("串口连接状态已设置为: 未连接"); logErrorWithRateLimit("serial_disconnected_external", "串口连接状态已设置为: 未连接"); // 如果串口断开且轮询正在运行,自动暂停轮询 if (isRunning && !isPaused) { pausePolling(); @@ -668,9 +688,9 @@ } } return String.format("轮询状态: %s, 串口: %s, 间隔: %dms, 指令缓存: %d, 卡槽范围: %d-%d, 无卡: %d(100ms), 有卡: %d(10s)", return String.format("轮询状态: %s, 串口: %s, 间隔: %dms, 指令缓存: %d, 卡槽范围: %d-%d, 无卡: %d(100ms), 有卡: %d(10s)\n%s", status, serialStatus, pollingInterval, cacheSize, MIN_SLOT, MAX_SLOT, noCardCount, hasCardCount); noCardCount, hasCardCount, getMemoryStatus()); } /** @@ -699,7 +719,7 @@ if (isPaused) { // 恢复前检查串口连接 if (!checkSerialConnectionWithRetry()) { Errlog.logOperation("串口未连接,无法恢复轮询查询"); logErrorWithRateLimit("external_resume_serial_failed", "串口未连接,无法恢复轮询查询"); return false; } @@ -756,7 +776,7 @@ */ public static void setNoCardQueryInterval(int interval) { if (interval < 10) { Errlog.logOperation("无卡卡槽查询间隔不能小于10ms"); logErrorWithRateLimit("no_card_interval_too_small", "无卡卡槽查询间隔不能小于10ms"); return; } // 注意:这里只是设置常量,实际运行时需要重新启动轮询才能生效 @@ -769,7 +789,7 @@ */ public static void setHasCardQueryInterval(int interval) { if (interval < 1000) { Errlog.logOperation("有卡卡槽查询间隔不能小于1000ms"); logErrorWithRateLimit("has_card_interval_too_small", "有卡卡槽查询间隔不能小于1000ms"); return; } // 注意:这里只是设置常量,实际运行时需要重新启动轮询才能生效 @@ -783,4 +803,102 @@ public static void setDEBUG_ENABLED(boolean dEBUG_ENABLED) { DEBUG_ENABLED = dEBUG_ENABLED; } // ==================== 新增内存优化方法 ==================== /** * 清理旧缓存 - 防止内存无限增长 */ private static void cleanupOldCache() { long currentTime = System.currentTimeMillis(); if (currentTime - lastCleanupTime < CACHE_CLEANUP_INTERVAL) { return; } lastCleanupTime = currentTime; // 清理长时间未使用的查询时间记录 long cleanupThreshold = currentTime - 300000; // 5分钟未使用 lastQueryTimeMap.entrySet().removeIf(entry -> currentTime - entry.getValue() > cleanupThreshold ); // 限制查询指令缓存大小 if (queryCommandCache.size() > MAX_CACHE_SIZE) { Iterator<Map.Entry<Integer, String>> iterator = queryCommandCache.entrySet().iterator(); int itemsToRemove = queryCommandCache.size() - MAX_CACHE_SIZE; for (int i = 0; i < itemsToRemove && iterator.hasNext(); i++) { iterator.next(); iterator.remove(); } } // 清理错误日志限流记录 lastErrorLogTime.entrySet().removeIf(entry -> currentTime - entry.getValue() > 300000 // 5分钟 ); } /** * 限流错误日志 - 防止大量重复日志占用内存 */ private static void logErrorWithRateLimit(String errorKey, String message) { long currentTime = System.currentTimeMillis(); Long lastTime = lastErrorLogTime.get(errorKey); if (lastTime == null || currentTime - lastTime > ERROR_LOG_INTERVAL) { Errlog.logOperation(message); lastErrorLogTime.put(errorKey, currentTime); // 清理过期的错误记录 if (lastErrorLogTime.size() > 50) { lastErrorLogTime.entrySet().removeIf(entry -> currentTime - entry.getValue() > 300000 // 5分钟 ); } } } /** * 获取内存状态信息 */ public static String getMemoryStatus() { Runtime runtime = Runtime.getRuntime(); long totalMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); long usedMemory = totalMemory - freeMemory; long maxMemory = runtime.maxMemory(); return String.format("内存使用: %.2fMB/%.2fMB (最大: %.2fMB), 缓存: 时间记录=%d, 指令缓存=%d, 错误记录=%d", usedMemory / (1024.0 * 1024.0), totalMemory / (1024.0 * 1024.0), maxMemory / (1024.0 * 1024.0), lastQueryTimeMap.size(), queryCommandCache.size(), lastErrorLogTime.size()); } /** * 手动触发内存清理 */ public static void performCleanup() { // 清理查询时间记录中长时间未查询的卡槽 long cleanupThreshold = System.currentTimeMillis() - 3600000; // 1小时 lastQueryTimeMap.entrySet().removeIf(entry -> entry.getValue() < cleanupThreshold ); // 清空查询指令缓存 queryCommandCache.clear(); // 清空错误日志限流记录 lastErrorLogTime.clear(); // 建议系统进行垃圾回收(但不强制) System.gc(); if (DEBUG_ENABLED) { SystemDebugDialog.appendAsciiData("执行内存清理完成\n"); } } } src/publicway/ProtocolParser01.java
@@ -1,14 +1,20 @@ package publicway; import java.util.ArrayList; import java.util.List; import chuankou.SerialPortService; import chushihua.SlotManager; import dialog.Errlog; public class ProtocolParser01 { // 缓存常用字符串减少重复创建 private static final String[] WORK_STATUS_DESC = {"无效", "待机", "充电", "充满", "故障", "授权到期", "通信超时", "未知状态"}; private static final String[] DOOR_STATUS_DESC = {"未知状态", "开门状态", "关门状态"}; private static final String[] CARD_STATUS_DESC = {"无卡", "有卡", "读卡错误(卡非法)", "未知状态"}; // StringBuilder 对象池 private static final ThreadLocal<StringBuilder> stringBuilderPool = ThreadLocal.withInitial(() -> new StringBuilder(512)); /** * 新增:直接使用字节数组解析的方法(避免字符串转换) * 优化后的字节数组解析方法 */ public static ParseResult parseDDCC01Data(byte[] packetData) { if (packetData == null || packetData.length < 18) { @@ -20,45 +26,49 @@ throw new IllegalArgumentException("非DDCC协议数据"); } ParseResult result = ParseResultPool.borrowObject(); try { // 跳过包头DDCC (2字节),直接使用剩余数据 byte[] dataBytes = new byte[packetData.length - 2]; System.arraycopy(packetData, 2, dataBytes, 0, dataBytes.length); if (dataBytes.length < 16) { // 直接使用原数组,避免创建新数组 if (packetData.length < 18) { // 2(包头) + 16(最小数据长度) throw new IllegalArgumentException("数据长度不足"); } // 2. 解析各个字段 int dataLength = parseDataLength(dataBytes); int hostAddress = parseHostAddress(dataBytes); int slotNumber = parseSlotNumber(dataBytes); int functionCode = parseFunctionCode(dataBytes); WorkStatus workStatus = parseWorkStatus(dataBytes); DoorStatus doorStatus = parseDoorStatus(dataBytes); CardStatus cardStatus = parseCardStatus(dataBytes); int cardStatusChange = parseCardStatusChange(dataBytes); String cardNumber = parseCardNumber(dataBytes); List<FaultType> faults = parseFaults(dataBytes); double voltage = parseVoltage(dataBytes); double current = parseCurrent(dataBytes); // 解析各个字段 int dataLength = parseDataLength(packetData, 2); int hostAddress = parseHostAddress(packetData, 4); int slotNumber = parseSlotNumber(packetData, 5); int functionCode = parseFunctionCode(packetData, 6); // 3. 验证功能码 // 验证功能码 if (functionCode != 0x01) { throw new IllegalArgumentException("非01功能码数据"); } return new ParseResult(hostAddress, slotNumber, workStatus, doorStatus, cardStatus, cardStatusChange, cardNumber, faults, voltage, current, dataLength); WorkStatus workStatus = parseWorkStatus(packetData, 7); DoorStatus doorStatus = parseDoorStatus(packetData, 8); CardStatus cardStatus = parseCardStatus(packetData, 9); int cardStatusChange = parseCardStatusChange(packetData, 10); String cardNumber = parseCardNumber(packetData, 13); List<FaultType> faults = parseFaults(packetData, 15); double voltage = parseVoltage(packetData, 16); double current = parseCurrent(packetData, 17); // 重用 ParseResult 对象 result.reset(hostAddress, slotNumber, workStatus, doorStatus, cardStatus, cardStatusChange, cardNumber, faults, voltage, current, dataLength); return result; } catch (Exception e) { // 发生异常时归还对象 ParseResultPool.returnObject(result); throw new RuntimeException("解析数据时发生错误: " + e.getMessage(), e); } } /** * 保留原有方法用于兼容性 * 优化后的字符串解析方法 */ public static ParseResult parseDDCC01Data(String hexData) { if (hexData == null || hexData.isEmpty()) { @@ -70,6 +80,7 @@ throw new IllegalArgumentException("非DDCC协议数据"); } ParseResult result = ParseResultPool.borrowObject(); try { // 1. 移除包头DDCC进行解析 String dataWithoutHeader = hexData.substring(4); @@ -80,179 +91,162 @@ } // 2. 解析各个字段 int dataLength = parseDataLength(dataBytes); int hostAddress = parseHostAddress(dataBytes); int slotNumber = parseSlotNumber(dataBytes); int functionCode = parseFunctionCode(dataBytes); WorkStatus workStatus = parseWorkStatus(dataBytes); DoorStatus doorStatus = parseDoorStatus(dataBytes); CardStatus cardStatus = parseCardStatus(dataBytes); int cardStatusChange = parseCardStatusChange(dataBytes); String cardNumber = parseCardNumber(dataBytes); List<FaultType> faults = parseFaults(dataBytes); double voltage = parseVoltage(dataBytes); double current = parseCurrent(dataBytes); int dataLength = parseDataLength(dataBytes, 0); int hostAddress = parseHostAddress(dataBytes, 2); int slotNumber = parseSlotNumber(dataBytes, 3); int functionCode = parseFunctionCode(dataBytes, 4); // 3. 验证功能码 if (functionCode != 0x01) { throw new IllegalArgumentException("非01功能码数据"); } return new ParseResult(hostAddress, slotNumber, workStatus, doorStatus, cardStatus, cardStatusChange, cardNumber, faults, voltage, current, dataLength); WorkStatus workStatus = parseWorkStatus(dataBytes, 5); DoorStatus doorStatus = parseDoorStatus(dataBytes, 6); CardStatus cardStatus = parseCardStatus(dataBytes, 7); int cardStatusChange = parseCardStatusChange(dataBytes, 8); String cardNumber = parseCardNumber(dataBytes, 11); List<FaultType> faults = parseFaults(dataBytes, 13); double voltage = parseVoltage(dataBytes, 14); double current = parseCurrent(dataBytes, 15); result.reset(hostAddress, slotNumber, workStatus, doorStatus, cardStatus, cardStatusChange, cardNumber, faults, voltage, current, dataLength); return result; } catch (Exception e) { ParseResultPool.returnObject(result); throw new RuntimeException("解析数据时发生错误: " + e.getMessage(), e); } } /** * CRC校验 * 根据协议:CRC16校验从功能码之后一直到CRC16之前的数据 */ @SuppressWarnings("unused") private static boolean validateCRC(String hexData) { try { // CRC在最后4个字符 String receivedCRC = hexData.substring(hexData.length() - 6); byte[] cmdBytes = HexUtil.hexStringToBytes(hexData.replace(receivedCRC,"")); String crc = HexUtil.calculate(cmdBytes)+"00"; //System.out.println("收到的完整数据是:"+hexData); //System.out.println("收到数据校验码是:"+receivedCRC); //System.out.println("校验码是:"+crc); return receivedCRC.equalsIgnoreCase(crc); } catch (Exception e) { Errlog.logOperation("CRC校验异常: " + e.getMessage()); return false; } } /** * 解析数据长度(2字节) * 数据长度是从该字节之后开始到CRC16之前数据字节数 */ private static int parseDataLength(byte[] data) { if (data.length < 2) { private static int parseDataLength(byte[] data, int offset) { if (data.length < offset + 2) { throw new IllegalArgumentException("数据长度不足,无法解析数据长度"); } return ((data[0] & 0xFF) << 8) | (data[1] & 0xFF); return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF); } /** * 解析主机地址(1字节) */ private static int parseHostAddress(byte[] data) { if (data.length < 3) { private static int parseHostAddress(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("数据长度不足,无法解析主机地址"); } return data[2] & 0xFF; return data[offset] & 0xFF; } /** * 解析卡槽编号(1字节) */ private static int parseSlotNumber(byte[] data) { if (data.length < 4) { private static int parseSlotNumber(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("数据长度不足,无法解析卡槽编号"); } return data[3] & 0xFF; return data[offset] & 0xFF; } /** * 解析功能码(1字节) */ private static int parseFunctionCode(byte[] data) { if (data.length < 5) { private static int parseFunctionCode(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("数据长度不足,无法解析功能码"); } return data[4] & 0xFF; return data[offset] & 0xFF; } /** * 解析工作状态(1字节) */ private static WorkStatus parseWorkStatus(byte[] data) { if (data.length < 6) { private static WorkStatus parseWorkStatus(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("数据长度不足,无法解析工作状态"); } int statusValue = data[5] & 0xFF; int statusValue = data[offset] & 0xFF; return WorkStatus.fromValue(statusValue); } /** * 解析在位状态/门状态(1字节) */ private static DoorStatus parseDoorStatus(byte[] data) { if (data.length < 7) { private static DoorStatus parseDoorStatus(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("数据长度不足,无法解析在位状态"); } int statusValue = data[6] & 0xFF; int statusValue = data[offset] & 0xFF; return DoorStatus.fromValue(statusValue); } /** * 解析卡状态(1字节) */ private static CardStatus parseCardStatus(byte[] data) { if (data.length < 8) { private static CardStatus parseCardStatus(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("数据长度不足,无法解析卡状态"); } int statusValue = data[7] & 0xFF; int statusValue = data[offset] & 0xFF; return CardStatus.fromValue(statusValue); } /** * 解析卡状态变更(1字节) */ private static int parseCardStatusChange(byte[] data) { if (data.length < 9) { private static int parseCardStatusChange(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("数据长度不足,无法解析卡状态变更"); } return data[8] & 0xFF; return data[offset] & 0xFF; } /** * 解析卡号(卡号3 + 卡号4) */ private static String parseCardNumber(byte[] data) { if (data.length < 13) { private static String parseCardNumber(byte[] data, int offset) { if (data.length < offset + 2) { throw new IllegalArgumentException("数据长度不足,无法解析卡号"); } // 索引11:卡号3,索引12:卡号4 byte cardNumber3 = data[11]; byte cardNumber4 = data[12]; return String.format("%02X%02X", cardNumber3 & 0xFF, cardNumber4 & 0xFF); // 直接返回字符串,避免创建临时对象 char[] hexChars = new char[4]; hexChars[0] = Character.forDigit((data[offset] >> 4) & 0xF, 16); hexChars[1] = Character.forDigit(data[offset] & 0xF, 16); hexChars[2] = Character.forDigit((data[offset + 1] >> 4) & 0xF, 16); hexChars[3] = Character.forDigit(data[offset + 1] & 0xF, 16); return new String(hexChars).toUpperCase(); } /** * 解析故障信息(1字节) */ private static List<FaultType> parseFaults(byte[] data) { if (data.length < 14) { private static List<FaultType> parseFaults(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("数据长度不足,无法解析故障信息"); } int faultByte = data[13] & 0xFF; List<FaultType> faults = new ArrayList<>(); int faultByte = data[offset] & 0xFF; List<FaultType> faults = new ArrayList<>(5); // 预分配容量 for (FaultType fault : FaultType.values()) { if ((faultByte & fault.getBitMask()) != 0) { faults.add(fault); } } return faults; } /** * 解析电压值(1字节) */ private static double parseVoltage(byte[] data) { if (data.length < 15) { private static double parseVoltage(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("数据长度不足,无法解析电压"); } int voltageValue = data[14] & 0xFF; int voltageValue = data[offset] & 0xFF; // 50mV/bit 转换为伏特 return voltageValue * 0.05; } @@ -260,18 +254,16 @@ /** * 解析电流值(1字节) */ private static double parseCurrent(byte[] data) { if (data.length < 16) { private static double parseCurrent(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("数据长度不足,无法解析电流"); } int currentValue = data[15] & 0xFF; int currentValue = data[offset] & 0xFF; // 10mA/bit 转换为安培 return currentValue * 0.01; } /** * 工作状态枚举 */ // 枚举类保持不变... public enum WorkStatus { INVALID(0, "无效"), STANDBY(1, "待机"), @@ -290,13 +282,8 @@ this.description = description; } public int getValue() { return value; } public String getDescription() { return description; } public int getValue() { return value; } public String getDescription() { return description; } public static WorkStatus fromValue(int value) { for (WorkStatus status : values()) { @@ -308,9 +295,6 @@ } } /** * 门状态枚举 */ public enum DoorStatus { UNKNOWN(0, "δ֪״̬"), DOOR_OPEN(1, "开门状态"), @@ -324,13 +308,8 @@ this.description = description; } public int getValue() { return value; } public String getDescription() { return description; } public int getValue() { return value; } public String getDescription() { return description; } public static DoorStatus fromValue(int value) { for (DoorStatus status : values()) { @@ -342,9 +321,6 @@ } } /** * 卡状态枚举 */ public enum CardStatus { NO_CARD(0, "无卡"), HAS_CARD(1, "有卡"), @@ -359,13 +335,8 @@ this.description = description; } public int getValue() { return value; } public String getDescription() { return description; } public int getValue() { return value; } public String getDescription() { return description; } public static CardStatus fromValue(int value) { for (CardStatus status : values()) { @@ -377,9 +348,6 @@ } } /** * 故障类型枚举 */ public enum FaultType { INSERT_ERROR(0x01, "插卡错误"), OVER_CURRENT(0x02, "过流"), @@ -395,17 +363,12 @@ this.description = description; } public int getBitMask() { return bitMask; } public String getDescription() { return description; } public int getBitMask() { return bitMask; } public String getDescription() { return description; } } /** * 解析结果类 - 添加对象池支持 * 优化后的解析结果类 */ public static class ParseResult { private int hostAddress; @@ -420,29 +383,12 @@ private double current; private int dataLength; // 默认构造器用于对象池 // 重用列表对象 private final List<FaultType> faultList = new ArrayList<>(5); private final List<String> faultDescList = new ArrayList<>(5); public ParseResult() {} public ParseResult(int hostAddress, int slotNumber, WorkStatus workStatus, DoorStatus doorStatus, CardStatus cardStatus, int cardStatusChange, String cardNumber, List<FaultType> faults, double voltage, double current, int dataLength) { this.hostAddress = hostAddress; this.slotNumber = slotNumber; this.workStatus = workStatus; this.doorStatus = doorStatus; this.cardStatus = cardStatus; this.cardStatusChange = cardStatusChange; this.cardNumber = cardNumber; this.faults = faults; this.voltage = voltage; this.current = current; this.dataLength = dataLength; } /** * 重置方法,用于对象重用 */ public void reset(int hostAddress, int slotNumber, WorkStatus workStatus, DoorStatus doorStatus, CardStatus cardStatus, int cardStatusChange, String cardNumber, List<FaultType> faults, double voltage, @@ -454,10 +400,16 @@ this.cardStatus = cardStatus; this.cardStatusChange = cardStatusChange; this.cardNumber = cardNumber; this.faults = faults; this.voltage = voltage; this.current = current; this.dataLength = dataLength; // 重用故障列表 this.faultList.clear(); if (faults != null) { this.faultList.addAll(faults); } this.faults = this.faultList; } // Getter方法 @@ -477,21 +429,24 @@ * 获取故障的中文描述列表 */ public List<String> getFaultDescriptions() { List<String> descriptions = new ArrayList<>(); faultDescList.clear(); for (FaultType fault : faults) { descriptions.add(fault.getDescription()); faultDescList.add(fault.getDescription()); } return descriptions; return faultDescList; } /** * 获取故障的中文描述字符串 */ public String getFaultsString() { if (faults == null || faults.isEmpty()) { if (faults.isEmpty()) { return "无故障"; } StringBuilder sb = new StringBuilder(); StringBuilder sb = stringBuilderPool.get(); sb.setLength(0); for (int i = 0; i < faults.size(); i++) { if (i > 0) sb.append(", "); sb.append(faults.get(i).getDescription()); @@ -501,7 +456,9 @@ @Override public String toString() { StringBuilder sb = new StringBuilder(); StringBuilder sb = stringBuilderPool.get(); sb.setLength(0); sb.append("1.主机地址:").append(String.format("%02X", hostAddress)); sb.append("2.卡槽编号:").append(slotNumber); sb.append("3.工作状态:").append(workStatus.getDescription()) @@ -515,34 +472,31 @@ sb.append("8.故障:").append(getFaultsString()); sb.append("9.电压:").append(String.format("%.2f", voltage)); sb.append("10.电流:").append(String.format("%.2f", current)); sb.append("数据长度:").append(dataLength).append(" 字节"); // System.out.println(sb.toString()); return sb.toString(); sb.append("数据长度:").append(dataLength).append(" 字节"); return sb.toString(); } public void fuzhi() { SlotManager.gengxinshuxingzhi( SlotManager.gengxinshuxingzhi( slotNumber, // 卡槽编号 cardNumber, // 卡编号 String.valueOf(cardStatus.getValue()), // 是否有卡0无卡,1有卡,-1未知 String.valueOf(workStatus.getValue()), // 工作状态0.无效1.待机;2.充电;3.充满;4.故障;5.授权到期;6.通信超时 String.valueOf(workStatus.getValue()), // 工作状态 String.format("%.2f", voltage), // 电压 String.format("%.2f", current), // 电流 getFaultsString() // 故障1插卡错误;2过流;3,门控故障;4过压;5欠压; ); getFaultsString() // 故障 ); } } /** * 简单的对象池实现 * 改进的对象池实现 */ public static class ParseResultPool { private static final int POOL_SIZE = 10; private static final int POOL_SIZE = 20; private static final java.util.concurrent.BlockingQueue<ParseResult> pool = new java.util.concurrent.ArrayBlockingQueue<>(POOL_SIZE); new java.util.concurrent.LinkedBlockingQueue<>(POOL_SIZE); static { // 预创建对象 @@ -557,9 +511,17 @@ } public static void returnObject(ParseResult result) { if (result != null && !pool.offer(result)) { // 池已满,不回收 if (result != null) { // 清理状态 result.reset(0, 0, WorkStatus.UNKNOWN, DoorStatus.UNKNOWN, CardStatus.UNKNOWN, 0, "", null, 0.0, 0.0, 0); // 非阻塞式归还 pool.offer(result); } } public static int getPoolSize() { return pool.size(); } } } src/publicway/SerialProtocolParser.java
@@ -1,4 +1,5 @@ package publicway; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executors; @@ -27,15 +28,15 @@ private static final byte FUNCTION_82 = (byte) 0x82; // 单板升级使能 private static final byte FUNCTION_83 = (byte) 0x83; // 单板升级数据包 // 数据缓冲区,用于处理粘包 // 数据缓冲区,用于处理粘包 - 改为直接ByteArrayOutputStream管理 private byte[] dataBuffer = new byte[1024]; private int bufferPosition = 0; // 数据接收队列 private BlockingQueue<byte[]> dataQueue = new ArrayBlockingQueue<>(100); // 数据接收队列 - 限制队列大小防止内存无限增长 private BlockingQueue<byte[]> dataQueue = new ArrayBlockingQueue<>(50); // 批量处理队列 private final BlockingQueue<byte[]> batchQueue = new ArrayBlockingQueue<>(1000); // 批量处理队列 - 限制队列大小 private final BlockingQueue<byte[]> batchQueue = new ArrayBlockingQueue<>(200); private final ScheduledExecutorService batchExecutor = Executors.newSingleThreadScheduledExecutor(); @@ -46,12 +47,18 @@ // 重用StringBuilder减少对象创建 private final StringBuilder hexBuilder = new StringBuilder(256); // 内存监控计数器 private long lastMemoryCheckTime = 0; private static final long MEMORY_CHECK_INTERVAL = 30000; // 30秒检查一次 // 对象池,减少对象创建 private final Object packetPoolLock = new Object(); /** * 启动解析器 */ public void start() { if (isRunning) { //System.out.println("串口协议解析器已经在运行中"); return; } @@ -63,8 +70,6 @@ processorThread = new Thread(this::processPackets, "Serial-Protocol-Parser"); processorThread.setDaemon(true); processorThread.start(); //System.out.println("串口协议解析器已启动 - 独立于轮询状态运行"); } /** @@ -99,11 +104,16 @@ } // 清空队列和缓冲区 clearQueues(); bufferPosition = 0; } /** * 清空所有队列,释放内存 */ private void clearQueues() { dataQueue.clear(); batchQueue.clear(); bufferPosition = 0; //System.out.println("串口协议解析器已停止"); } /** @@ -126,9 +136,31 @@ return; } // 将数据添加到批量队列 - 确保始终执行 // 检查队列状态,避免内存无限增长 if (batchQueue.size() > batchQueue.remainingCapacity() * 0.8) { // 队列接近满时,丢弃最老的数据 if (!batchQueue.isEmpty()) { batchQueue.poll(); // 移除一个旧数据 } } // 将数据添加到批量队列 if (!batchQueue.offer(rawData)) { System.err.println("批量队列已满,丢弃数据"); // 队列已满时的处理 handleQueueFull(); } } /** * 处理队列满的情况 */ private void handleQueueFull() { // 清空队列重新开始,避免内存泄漏 clearQueues(); bufferPosition = 0; // 重置缓冲区 if (lunxun.DEBUG_ENABLED) { SystemDebugDialog.appendAsciiData("警告:数据处理队列已满,已清空队列重新开始"); } } @@ -140,39 +172,105 @@ return; } // 批量处理数据 java.util.List<byte[]> batch = new java.util.ArrayList<>(100); batchQueue.drainTo(batch, 100); for (byte[] rawData : batch) { // 将数据添加到缓冲区 if (bufferPosition + rawData.length > dataBuffer.length) { // 缓冲区不足时,清理并重新开始 System.arraycopy(dataBuffer, bufferPosition - rawData.length, dataBuffer, 0, rawData.length); bufferPosition = rawData.length; } else { try { // 批量处理数据,限制每次处理的最大数量 int maxBatchSize = 50; java.util.List<byte[]> batch = new java.util.ArrayList<>(maxBatchSize); batchQueue.drainTo(batch, maxBatchSize); for (byte[] rawData : batch) { // 检查缓冲区容量,避免溢出 if (bufferPosition + rawData.length > dataBuffer.length) { // 缓冲区不足时的处理 if (rawData.length > dataBuffer.length) { // 单条数据超过缓冲区大小,直接处理或丢弃 handleOversizedPacket(rawData); continue; } else { // 移动有效数据到缓冲区开头 compactBuffer(0); } } // 将数据添加到缓冲区 System.arraycopy(rawData, 0, dataBuffer, bufferPosition, rawData.length); bufferPosition += rawData.length; // 处理缓冲区中的数据 processBuffer(); } // 处理缓冲区中的数据 processBuffer(); // 定期检查内存 checkMemory(); } catch (Exception e) { System.err.println("批量处理数据时发生异常: " + e.getMessage()); // 发生异常时重置状态 resetParserState(); } // 定期检查内存 checkMemory(); } /** * 处理过大的数据包 */ private void handleOversizedPacket(byte[] oversizedData) { // 对于过大的数据包,直接尝试查找起始标记 int startIndex = findStartMarkerInArray(oversizedData, 0); if (startIndex != -1) { // 找到起始标记,将剩余数据放入缓冲区 int remainingLength = oversizedData.length - startIndex; if (remainingLength <= dataBuffer.length) { System.arraycopy(oversizedData, startIndex, dataBuffer, 0, remainingLength); bufferPosition = remainingLength; processBuffer(); } } // 否则丢弃该数据包 } /** * 在指定数组中查找起始标记 */ private int findStartMarkerInArray(byte[] data, int startPos) { for (int i = startPos; i <= data.length - START_MARKER.length; i++) { if (data[i] == START_MARKER[0] && data[i + 1] == START_MARKER[1]) { return i; } } return -1; } /** * 重置解析器状态 */ private void resetParserState() { bufferPosition = 0; clearQueues(); } /** * 内存监控 */ private void checkMemory() { long currentTime = System.currentTimeMillis(); if (currentTime - lastMemoryCheckTime < MEMORY_CHECK_INTERVAL) { return; } lastMemoryCheckTime = currentTime; Runtime runtime = Runtime.getRuntime(); long usedMem = runtime.totalMemory() - runtime.freeMemory(); long maxMem = runtime.maxMemory(); if (usedMem > maxMem * 0.8) { //System.out.println("内存使用率超过80%,当前使用: " + (usedMem / 1024 / 1024) + "MB"); if (usedMem > maxMem * 0.75) { // 内存使用率超过75%时进行垃圾回收 System.gc(); if (lunxun.DEBUG_ENABLED) { SystemDebugDialog.appendAsciiData("内存使用率超过75%,已触发垃圾回收。使用内存: " + (usedMem / 1024 / 1024) + "MB"); } } } @@ -180,7 +278,10 @@ * 处理缓冲区中的数据,解析完整数据包 */ private void processBuffer() { while (bufferPosition >= MIN_PACKET_LENGTH) { int processedCount = 0; final int MAX_PACKETS_PER_BATCH = 20; // 限制每次处理的最大包数量 while (bufferPosition >= MIN_PACKET_LENGTH && processedCount < MAX_PACKETS_PER_BATCH) { // 查找起始标记 int startIndex = findStartMarker(); if (startIndex == -1) { @@ -200,6 +301,13 @@ int dataLength = ((dataBuffer[startIndex + 2] & 0xFF) << 8) | (dataBuffer[startIndex + 3] & 0xFF); int totalPacketLength = 2 + 2 + dataLength + 2; // 起始标记2 + 数据长度2 + 数据内容 + CRC2 // 检查数据长度是否合理 if (dataLength < 0 || totalPacketLength > dataBuffer.length) { // 数据长度异常,跳过这个包 compactBuffer(startIndex + 1); continue; } // 检查是否收到完整数据包 if (startIndex + totalPacketLength > bufferPosition) { // 数据包不完整,等待更多数据 @@ -208,16 +316,15 @@ } // 提取完整数据包 byte[] packet = new byte[totalPacketLength]; System.arraycopy(dataBuffer, startIndex, packet, 0, totalPacketLength); // 将数据包放入队列供解析 try { byte[] packet = extractPacket(startIndex, totalPacketLength); if (packet != null) { // 将数据包放入队列供解析 if (!dataQueue.offer(packet)) { System.err.println("数据队列已满,丢弃数据包"); // 队列已满,释放packet引用 packet = null; handleDataQueueFull(); return; } } catch (Exception e) { System.err.println("放入数据队列时发生异常: " + e.getMessage()); } // 移动缓冲区位置 @@ -226,6 +333,29 @@ System.arraycopy(dataBuffer, startIndex + totalPacketLength, dataBuffer, 0, remaining); } bufferPosition = remaining; processedCount++; } } /** * 提取数据包,重用byte数组减少对象创建 */ private byte[] extractPacket(int startIndex, int totalPacketLength) { byte[] packet = new byte[totalPacketLength]; System.arraycopy(dataBuffer, startIndex, packet, 0, totalPacketLength); return packet; } /** * 处理数据队列满的情况 */ private void handleDataQueueFull() { // 丢弃队列中最老的数据 dataQueue.poll(); if (lunxun.DEBUG_ENABLED) { SystemDebugDialog.appendAsciiData("数据解析队列已满,丢弃最老数据包"); } } @@ -245,7 +375,7 @@ * 压缩缓冲区,将有效数据移到开头 */ private void compactBuffer(int startIndex) { if (startIndex > 0) { if (startIndex > 0 && bufferPosition > startIndex) { System.arraycopy(dataBuffer, startIndex, dataBuffer, 0, bufferPosition - startIndex); bufferPosition -= startIndex; } @@ -267,7 +397,7 @@ break; } catch (Exception e) { System.err.println("处理数据包时发生异常: " + e.getMessage()); e.printStackTrace(); // 继续运行,不退出线程 } } @@ -278,8 +408,12 @@ * 解析数据包并根据功能码调用相应方法 */ private void parsePacket(byte[] packet) { if (packet == null || packet.length < MIN_PACKET_LENGTH) { return; } try { SerialPortService.getReceivedDataCount(); SerialPortService.getReceivedDataCount(); // 解析基本字段 byte hostAddress = packet[4]; // 主机地址 byte slotAddress = packet[5]; // 卡槽地址 @@ -290,7 +424,7 @@ // 返回值数据 int returnValueLength = dataLength - 3; // N-3 (减去主机地址、卡槽地址、功能码) byte[] returnValue = null; if (returnValueLength > 0) { if (returnValueLength > 0 && returnValueLength <= packet.length - 7) { returnValue = new byte[returnValueLength]; System.arraycopy(packet, 7, returnValue, 0, returnValueLength); } @@ -301,12 +435,12 @@ if (returnValue != null) { // 使用优化的字节数组解析方法,避免字符串转换 ParseResult rst = ProtocolParser01.parseDDCC01Data(packet); rst.fuzhi(); // System.out.println(rst.toString()); if (lunxun.DEBUG_ENABLED) { SystemDebugDialog.appendAsciiData(rst.toString()); if (rst != null) { rst.fuzhi(); if (lunxun.DEBUG_ENABLED) { SystemDebugDialog.appendAsciiData(rst.toString()); } } } break; case FUNCTION_51: @@ -315,36 +449,37 @@ int result = ProtocolParser51.parse(hexPacket); int slot = slotAddress; if (result == 1) { // Dingshidialog.showTimedDialog(null, 5,slot+"号卡槽出卡成功请取走卡..."); SlotManager.changgehaska(slot, result); SlotManager.changgehaska(slot, result); } else { String message=slot+"号卡槽取卡失败"; String message = slot + "号卡槽取卡失败"; Charulog.logOperation(message); } break; case FUNCTION_52: //System.out.println("功能码 0x52 - LED亮度控制"); // LED亮度控制 - 无操作 break; case FUNCTION_80: //System.out.println("功能码 0x80 - 工卡升级使能"); // 工卡升级使能 - 无操作 break; case FUNCTION_81: //System.out.println("功能码 0x81 - 工作卡升级数据包"); // 工作卡升级数据包 - 无操作 break; case FUNCTION_82: //System.out.println("功能码 0x82 - 单板升级使能"); // 单板升级使能 - 无操作 break; case FUNCTION_83: //System.out.println("功能码 0x83 - 单板升级数据包"); // 单板升级数据包 - 无操作 break; default: System.err.println("未知功能码: 0x" + Integer.toHexString(functionCode & 0xFF)); if (lunxun.DEBUG_ENABLED) { System.err.println("未知功能码: 0x" + Integer.toHexString(functionCode & 0xFF)); } break; } } catch (Exception e) { System.err.println("解析数据包时发生错误: " + e.getMessage()); e.printStackTrace(); // 不打印堆栈跟踪,避免产生大量日志对象 } } @@ -352,6 +487,10 @@ * 优化的字节数组转十六进制字符串方法 */ private String bytesToHex(byte[] bytes) { if (bytes == null || bytes.length == 0) { return ""; } hexBuilder.setLength(0); // 清空重用 for (byte b : bytes) { hexBuilder.append(String.format("%02X", b)); @@ -390,12 +529,14 @@ * 获取解析器状态信息 */ public String getStatusInfo() { return String.format("串口解析器状态: %s, 队列大小: %d/%d, 批量队列: %d/%d", return String.format("串口解析器状态: %s, 队列大小: %d/%d, 批量队列: %d/%d, 缓冲区: %d/%d", isRunning ? "运行中" : "已停止", dataQueue.size(), dataQueue.remainingCapacity() + dataQueue.size(), batchQueue.size(), batchQueue.remainingCapacity() + batchQueue.size()); batchQueue.remainingCapacity() + batchQueue.size(), bufferPosition, dataBuffer.length); } /** @@ -404,4 +545,14 @@ public void setMaxRawDataPrintLength(int length) { // 实现根据需要调整 } /** * 主动清理资源 */ public void cleanup() { stop(); clearQueues(); bufferPosition = 0; hexBuilder.setLength(0); } } src/xitongshezhi/kuaisuquka.java
@@ -140,12 +140,7 @@ String hasCardStatus = slotInfo.getHasCard(); String cardNumber = slotInfo.getCardNumber(); // 调试单个卡槽 if (i < 5) { // 只打印前5个卡槽的调试信息 System.out.printf("刷新卡槽 %d: hasCard=%s, cardNumber=%s%n", i + 1, hasCardStatus, cardNumber); } // 简化的判断逻辑 - 重点调试 boolean reallyHasCard = false;