CommSendService.java 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291
  1. package com.ruoyi.sim.service.impl;
  2. import com.ruoyi.common.core.domain.AjaxResult;
  3. import com.ruoyi.common.utils.DateUtils;
  4. import com.ruoyi.sim.config.SimConfig;
  5. import com.ruoyi.sim.constant.CommConst;
  6. import com.ruoyi.sim.constant.FaultIdConst;
  7. import com.ruoyi.sim.domain.*;
  8. import com.ruoyi.sim.domain.vo.FaultCheckVo;
  9. import com.ruoyi.sim.domain.vo.ScanSeatVo;
  10. import com.ruoyi.sim.domain.vo.SimSocketParamVo;
  11. import com.ruoyi.sim.util.SimDateUtil;
  12. import org.apache.commons.collections4.SetUtils;
  13. import org.apache.commons.lang3.StringUtils;
  14. import org.slf4j.LoggerFactory;
  15. import org.slf4j.Logger;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.scheduling.annotation.Async;
  18. import org.springframework.stereotype.Service;
  19. import org.springframework.transaction.annotation.Transactional;
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.io.OutputStream;
  23. import java.net.Socket;
  24. import java.util.*;
  25. import static com.ruoyi.sim.constant.CommConst.*;
  26. /**
  27. * 硬件通信
  28. * send service.
  29. * "commSendService"
  30. */
  31. @Service
  32. public class CommSendService {
  33. private static final Logger l = LoggerFactory.getLogger(CommSendService.class);
  34. @Autowired
  35. private CommReceiveService simReceiveService;
  36. @Autowired
  37. private SeatService seatService;
  38. @Autowired
  39. private SimService simService;
  40. @Autowired
  41. private FaultService faultService;
  42. @Autowired
  43. private RealExamService realExamService;
  44. @Autowired
  45. private RealExamFaultService realExamFaultService;
  46. @Autowired
  47. private RealExamCollectionService realExamCollectionService;
  48. @Autowired
  49. private CommBuildService commBuildService;
  50. @Autowired
  51. private DebugFaultService debugFaultService;
  52. @Autowired
  53. private SocketService socketService;
  54. @Autowired
  55. private CommCheckService commCheckService;
  56. @Autowired
  57. private CommReceiveService commReceiveService;
  58. @Autowired
  59. private SimConfig config;
  60. @Autowired
  61. private CommStrategy commStrategy;
  62. @Autowired
  63. private CmdService cmdService;
  64. /**
  65. * 定时任务。
  66. */
  67. public void scheduledLoopRead() {
  68. readAll();
  69. }
  70. public void readAll() {
  71. l.info("readAll");
  72. List<RealExam> listRe = realExamService.listAllByStatus(RealExam.State.ANSWERING);
  73. listRe.forEach(e -> {
  74. if (e == null) {
  75. return;
  76. }
  77. List<RealExamFault> listRef = realExamFaultService.listAllType2State2and3ByExamId(e.getExamId());
  78. listRef.forEach(ref -> {
  79. RealExam re = realExamService.selectRealExamByExamId(ref.getExamId());
  80. Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
  81. Sim sim = simService.selectSimBySimId(e.getSimId());
  82. Fault fault = faultService.selectFaultByFaultId(ref.getFaultId());
  83. if (fault != null && Fault.Type.REAL_GZBW.equals(fault.getFaultType()) && Fault.State.ENABLE.equals(fault.getFaultState())) {
  84. readOneSimOneFaultResistance(seat, sim, ref, fault, null);
  85. }
  86. });
  87. });
  88. }
  89. /**
  90. * Async version.
  91. */
  92. @Async("tp-comm")
  93. public void readAllAsync() {
  94. readAll();
  95. }
  96. /**
  97. * 开始考试以后,交卷之前,定时任务中间读取值,作为答题值。有优先级高的任务可能跳过执行。
  98. *
  99. * @param re
  100. */
  101. public void readOneExamAtMiddle(RealExam re) {
  102. l.info("readOneExamAtMiddle getExamId = {}", re.getExamId());
  103. List<RealExamFault> list = realExamFaultService.listAllType2State2and3ByExamId(re.getExamId());
  104. for (RealExamFault ref : list) {
  105. {
  106. RealExamFault refQ = realExamFaultService.selectRealExamFaultByRefId(ref.getRefId());
  107. if (refQ == null || refQ.getExamId() == 0L) {
  108. continue;
  109. }
  110. if (!RealExamFault.State.WRITTEN.equals(ref.getRefState()) && !RealExamFault.State.LOOP_READ.equals(ref.getRefState())) {
  111. continue;
  112. }
  113. }
  114. Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
  115. Sim sim = simService.selectSimBySimId(re.getSimId());
  116. Fault fault = faultService.selectFaultByFaultId(ref.getFaultId());
  117. readOneSimOneFaultResistance(seat, sim, ref, fault, RealExamFault.State.LOOP_READ);
  118. }
  119. }
  120. /**
  121. * 交卷最后读取值,作为答题值。
  122. *
  123. * @param re
  124. */
  125. public void readOneExamAtLast(RealExam re) {
  126. l.info("readOneExamAtLast getExamId = {}", re.getExamId());
  127. List<RealExamFault> list = realExamFaultService.listAllType2State2and3ByExamId(re.getExamId());
  128. for (RealExamFault ref : list) {
  129. Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
  130. Sim sim = simService.selectSimBySimId(re.getSimId());
  131. Fault fault = faultService.selectFaultByFaultId(ref.getFaultId());
  132. readOneSimOneFaultResistance(seat, sim, ref, fault, RealExamFault.State.FINISH);
  133. }
  134. // 计算扣分。
  135. // 最后都读取到,才算扣分。
  136. {
  137. // todo:暂时不算。
  138. // calculateScore(re.getExamId());
  139. }
  140. }
  141. public void readOneSimAtLastByDebug(Seat seat, Sim sim) {
  142. l.info("readOneSimAtLastByDebug");
  143. List<Fault> list = faultService.listType3(sim.getSimType());
  144. for (Fault fault : list) {
  145. readOneSimOneFaultResistance(seat, sim, null, fault, null);
  146. }
  147. }
  148. public AjaxResult debugReadAllFaultResistanceBySimNum(final Long seatId) {
  149. // check
  150. if (seatId == null || seatId == 0L) {
  151. return AjaxResult.error("尚未选择座次。");
  152. }
  153. //
  154. // 打开socket
  155. {
  156. socketService.tryOpenAll();
  157. }
  158. //
  159. Seat seat = seatService.selectSeatBySeatId(seatId);
  160. Sim sim = getSimBySeatIdNewVer(seatId);
  161. {
  162. AjaxResult arE3 = checkOneSimStateActive(seat);
  163. if (arE3.isError()) {
  164. return arE3;
  165. }
  166. }
  167. sim = simService.uniqueBySimNum(sim.getSimNum());
  168. // todo: aj改造
  169. readOneSimAtLastByDebug(seat, sim);
  170. return AjaxResult.success("成功读取!");
  171. }
  172. @Async("tp-comm")
  173. public void readOneExamAtLastAsync(RealExam re) {
  174. l.info("readOneExamAtLastAsync");
  175. readOneExamAtLast(re);
  176. }
  177. /**
  178. * 计算减分(不包括超时)。汇总到deduction_total_score字段。
  179. *
  180. * @param realExamId
  181. */
  182. public void calculateScore(Long realExamId) {
  183. realExamService.updateOneState(realExamId, RealExam.State.CALCULATING_SCORE);
  184. int minus = 0;
  185. // 排除故障部分 + 维修报告选择部分
  186. realExamFaultService.calculateMinusByRealExamId(realExamId);
  187. // 超时部分
  188. int timeoutMinute = 0;
  189. //
  190. realExamService.updateOneState(realExamId, RealExam.State.GOT_REPORT);
  191. }
  192. /**
  193. * todo:????
  194. * 定时任务。
  195. */
  196. public void scheduledReadSim() {
  197. l.info("scheduledReadSim");
  198. if (!realExamCollectionService.existAtLeastOneOpened()) {
  199. l.info("没有open的考试集合");
  200. return;
  201. }
  202. readAll();
  203. //
  204. // AA010102010000000055
  205. // AA010102010000000055
  206. String simNum = "01";
  207. String simType = "0002";
  208. // for (int i = 0; i < 3; i++) {
  209. // debugReadSimType(simNum);
  210. // }
  211. // debugClearAllFault(simNum, simType);
  212. // debugWriteAllFault(simNum, simType);
  213. // for (int i = 0; i < 3; i++) {
  214. // debugReadAllFaultResistance(simNum, simType);
  215. // }
  216. // debugClearOneFault(simNum, "02");
  217. // boolean bRea = isReachable("123.112.16.165");
  218. // debugReadSimType(simNum);
  219. // l.info("bRea:" + bRea);
  220. // debugReadAllFaultResistance(simNum, simType);
  221. // debugWriteAllFault(simNum, simType);
  222. // for (int i = 0; i < 5; i++) {
  223. // debugReadAllFaultResistance(simNum, simType);
  224. // }
  225. // if (isSocketOk()) {
  226. // readAllAsync();
  227. // } else {
  228. // scheduledConnect();
  229. // }
  230. }
  231. /**
  232. * 连接情况 的 定时任务。
  233. * 执行频率: 5min
  234. */
  235. public void scheduledConnect() {
  236. l.info("scheduled####Connect 连接情况 的 定时任务");
  237. // if (!SimDebugConfig.SCHEDULED_CONNECT) {
  238. if (true) {
  239. l.info("连接情况 的 定时任务被禁用!");
  240. return;
  241. }
  242. // 暂时注释
  243. // if (!realExamCollectionService.existAtLeastOneOpened()) {
  244. // l.info("没有open的任何集合");
  245. // return;
  246. // }
  247. //
  248. {
  249. AjaxResult ar = commCheckService.checkRouterState(config.getRouterIp());
  250. if (ar.isError()) {
  251. return;
  252. }
  253. }
  254. //
  255. {
  256. seatService.listAllRs485Ip().forEach(rs485Ip -> {
  257. commCheckService.checkPingRs485State(rs485Ip);
  258. });
  259. }
  260. // SocketOldService实现
  261. // if (socketOldService.isCachedSocketOk()) {
  262. // checkAllSeatAndSimState();
  263. // }
  264. socketService.tryOpenAll();
  265. commCheckService.checkAllSeatAndSimState();
  266. }
  267. /**
  268. * 每天06:00/12:00/18:00/00:00执行
  269. */
  270. public void scheduledCloseAllSocket() {
  271. l.info("scheduledCloseAllSocket");
  272. AjaxResult ar = socketService.closeAll();
  273. l.info("AjaxResult = {}", ar);
  274. }
  275. /**
  276. * 每30min运行一次。
  277. */
  278. public void scheduledSystemAutoCleanExam() {
  279. l.info("scheduledSystemAutoCleanExam");
  280. realExamService.systemAutoCleanExam();
  281. }
  282. /**
  283. * 每6hour运行一次。
  284. */
  285. public void scheduledProjectRestart() {
  286. l.info("scheduledProjectRestart");
  287. cmdService.restart();
  288. }
  289. /**
  290. * 主动更新模拟器状态。
  291. * <p>
  292. * <p>
  293. * 主动查询一次模拟器状态。更新模拟器在线/离线状态;否则返回对应错误。
  294. * todo:需要重新考虑,不再使用。
  295. *
  296. * @param seat
  297. * @return
  298. */
  299. @Deprecated
  300. public AjaxResult checkOneSimStateActive(Seat seat) {
  301. // 这句可能会调整模拟器状态,后面需要重新查询。
  302. commCheckService.checkOneSeatState(seat, true);
  303. AjaxResult ar1 = commCheckService.checkOneSimOnlineState(seat, true);
  304. if (ar1.isError()) {
  305. return ar1;
  306. }
  307. // 重新最新模拟器。
  308. Sim sim = getSimBySeatIdNewVer(seat.getSeatId());
  309. // 如果模拟器离线
  310. if (sim != null && Sim.State.ONLINE.equals(sim.getSimState())) {
  311. return AjaxResult.success();
  312. } else {
  313. return AjaxResult.error("未连接模拟器,请检查连接!");
  314. }
  315. }
  316. @Async("tp-comm")
  317. public void checkAllSimStateAsync() {
  318. commCheckService.checkAllSeatAndSimState();
  319. }
  320. /**
  321. * 清除一个考试的,对应的某型号一台模拟器的,所有故障部位。
  322. *
  323. * @param re
  324. */
  325. public void clearOneSimAllFaultByExam(RealExam re) {
  326. l.info("clearOneSimAllFaultByExam = {}", re);
  327. // check
  328. // 更新Exam状态。
  329. {
  330. realExamService.updateOneState(re.getExamId(), RealExam.State.SIM_WRITING);
  331. }
  332. //
  333. List<RealExamFault> list = realExamFaultService.listAllType2InitStateByExamId(re.getExamId());
  334. if (list != null) {
  335. l.info("清除exam list = {}", list.size());
  336. }
  337. assert list != null;
  338. Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
  339. list.forEach(ref -> {
  340. Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
  341. if (faultService.isDisable(f.getFaultId())) {
  342. l.warn("故障 {} -被禁用", f.getName());
  343. throw new IllegalArgumentException("故障被禁用");
  344. }
  345. Sim sim = simService.selectSimBySimId(re.getSimId());
  346. // check
  347. //
  348. clearOneSimOneFault(seat, sim, ref, f);
  349. });
  350. }
  351. public void clearOneSimAllFaultBySim(Seat seat, Sim sim) {
  352. l.info("clearOneSimAllFaultBySim = {}", sim);
  353. faultService.listType3EnableBySimType(sim.getSimType()).forEach(f -> {
  354. clearOneSimOneFault(seat, sim, null, f);
  355. });
  356. }
  357. /**
  358. * Async version.
  359. *
  360. * @param re
  361. */
  362. @Async("tp-comm")
  363. public void clearListFaultByRealExamAsync(RealExam re) {
  364. clearOneSimAllFaultByExam(re);
  365. }
  366. public void clearAll() {
  367. // todo:
  368. // 根据Seat数据遍历
  369. seatService.listAllEnable().forEach(seat -> {
  370. Sim sim = getSimBySeatIdNewVer(seat.getSeatId());
  371. String simType = sim.getSimType();
  372. List<Fault> listF = faultService.listType3EnableBySimType(simType);
  373. listF.forEach(f -> {
  374. clearOneSimOneFault(seat, sim, null, f);
  375. });
  376. });
  377. }
  378. /**
  379. * debug读取模拟器类型序列号
  380. *
  381. * @param seatId
  382. * @return
  383. */
  384. public SimMsg debugReadSimType(final Long seatId) {
  385. Seat seat = seatService.selectSeatBySeatId(seatId);
  386. Sim sim = getSimBySeatIdNewVer(seatId);
  387. SimMsg sm = commBuildService.buildSendMsgReadSimType(sim.getSimNum());
  388. return send(sm, seat, sim, CommConst.RETRY_COUNT_0, commStrategy.getSleepShort());
  389. }
  390. /**
  391. * debug清除一个故障
  392. *
  393. * @param seatId
  394. * @param bindHardwareMsg
  395. * @return
  396. */
  397. public SimMsg debugClearOneFault(final Long seatId, final String bindHardwareMsg) {
  398. Seat seat = seatService.selectSeatBySeatId(seatId);
  399. // Sim sim = getSimBySeatIdNewVer(seatId);
  400. // 不需要重复调用 getSimBySeatIdNewVer。
  401. Sim sim = simService.selectSimBySimId(seat.getCurrentSimId());
  402. SimMsg sm = commBuildService.buildSendMsgClearFault(sim.getSimNum(), bindHardwareMsg);
  403. return send(sm, seat, sim, RETRY_COUNT_CLEAR_ONE_FAULT, commStrategy.getSleepLong());
  404. }
  405. /**
  406. * debug清除所有座次上的模拟器的所有故障
  407. *
  408. * @return
  409. */
  410. public AjaxResult debugClearAllSeatAllFault() {
  411. debugFaultService.deleteAll();
  412. List<Seat> list = seatService.listAllEnable();
  413. for (Seat seat : list) {
  414. if (seat == null) {
  415. AjaxResult.error("座次数据异常!");
  416. }
  417. //
  418. commCheckService.checkOneSeatState(seat, true);
  419. // 重新查询
  420. seat = seatService.selectSeatBySeatId(seat.getSeatId());
  421. if (seat.getCurrentSimId() == null || seat.getCurrentSimId() == 0L) {
  422. continue;
  423. }
  424. AjaxResult ar = debugClearAllFaultBySeatId(seat.getSeatId());
  425. if (ar.isError()) {
  426. return ar;
  427. }
  428. }
  429. return AjaxResult.success("清除成功,清除所有座次正确连接的模拟器的,所有的故障!" + SimDateUtil.getNow());
  430. }
  431. /**
  432. * debug清除SeatId上模拟器所有故障
  433. *
  434. * @param seatId
  435. * @return
  436. */
  437. public AjaxResult debugClearAllFaultBySeatId(final Long seatId) {
  438. {
  439. AjaxResult ar = debugCheckSeatId(seatId);
  440. if (ar.isError()) {
  441. return ar;
  442. }
  443. }
  444. debugFaultService.deleteAll();
  445. Seat seat = seatService.selectSeatBySeatId(seatId);
  446. Sim sim = getSimBySeatIdNewVer(seatId);
  447. if (sim == null) {
  448. return AjaxResult.error("清除失败,模拟器不存在!请检查模拟器线缆连接,模拟器线缆开关!");
  449. }
  450. sim = simService.selectSimBySimId(sim.getSimId());
  451. if (!Sim.State.ONLINE.equals(sim.getSimState())) {
  452. return AjaxResult.error("清除失败,模拟器尚未在线!");
  453. }
  454. List<SimMsg> list = new ArrayList<>();
  455. for (String b : getGZBWBySimType(sim.getSimType())) {
  456. SimMsg sm = debugClearOneFault(seatId, b);
  457. if (sm != null && !Objects.equals(sm.getResult(), SimMsg.Result.SUCCESS)) {
  458. AjaxResult.error("清除失败!");
  459. }
  460. list.add(sm);
  461. }
  462. return AjaxResult.success("清除成功,清除当前模拟器所有的故障!" + SimDateUtil.getNow());
  463. }
  464. /**
  465. * @param sim
  466. * @param reF 可以为空,表示不关联考试的,单独执行的。调试模式下为空。
  467. * @param f
  468. */
  469. public void clearOneSimOneFault(Seat seat, Sim sim, RealExamFault reF, Fault f) {
  470. l.info("clearOneSimOneFault 清除One故障:getSimNum = {},getBindHardwareMsg = {},fault.getName = {}", sim.getSimNum(), f.getBindHardwareMsg(), f.getName());
  471. // check todo:
  472. // step1
  473. SimMsg smS = commBuildService.buildSendMsgClearFault(sim.getSimNum(), f.getBindHardwareMsg());
  474. SimMsg smR = send(smS, seat, sim, RETRY_COUNT_CLEAR_ONE_FAULT, commStrategy.getSleepLong());
  475. if (reF != null) {
  476. simReceiveService.clearOneFault(smR, sim, reF, f);
  477. } else {
  478. l.info("reF == null");
  479. }
  480. // step2
  481. // 下发故障独立运行。下面屏蔽。
  482. // if (reF != null &&
  483. // realExamFaultService.isState(reF.getRefId(), RealExamFault.State.CLEARED)) {
  484. // if (reF.getFlag().equals(RealExamFault.Flag.YES)) {
  485. // writeOneFault(s, reF, f);
  486. // } else if (reF.getFlag().equals(RealExamFault.Flag.NO)) {
  487. // RealExamFault f1 = realExamFaultService.selectRealExamFaultByRefId(reF.getRefId());
  488. // f1.setRefState(RealExamFault.State.LOOP_READ);
  489. // }
  490. // }
  491. }
  492. /**
  493. * debug下发一个故障
  494. *
  495. * @param seatId
  496. * @param bindHardwareMsg
  497. * @return
  498. * @throws IOException
  499. */
  500. public SimMsg debugWriteOneFault(final Long seatId, final String bindHardwareMsg) {
  501. Seat seat = seatService.selectSeatBySeatId(seatId);
  502. Sim sim = getSimBySeatIdNewVer(seatId);
  503. SimMsg sm = commBuildService.buildSendMsgWriteFault(sim.getSimNum(), bindHardwareMsg);
  504. return send(sm, seat, sim, RETRY_COUNT_WRITE_ONE_FAULT, commStrategy.getSleepLong());
  505. }
  506. /**
  507. * debug下发所有故障
  508. *
  509. * @param seatId
  510. * @return
  511. * @throws IOException
  512. */
  513. public List<SimMsg> debugWriteAllFault(final Long seatId) {
  514. List<SimMsg> list = new ArrayList<>();
  515. Sim sim = getSimBySeatIdNewVer(seatId);
  516. String simType = sim.getSimType();
  517. for (String bind : getGZBWBySimType(simType)) {
  518. list.add(debugWriteOneFault(seatId, bind));
  519. }
  520. return list;
  521. }
  522. /**
  523. * todo:尚未实现
  524. * 实现方式类似 studentStartRealExam方法。
  525. *
  526. * @param seatId
  527. * @param faultIds
  528. * @param checkReplace 是否进行可换件检查
  529. * @return
  530. */
  531. @Transactional
  532. public AjaxResult debugWriteSelectedFaultBySeatId(final Long seatId, final String[] faultIds, final Boolean checkReplace) {
  533. // Check:seatId有效性
  534. {
  535. AjaxResult ar = debugCheckSeatId(seatId);
  536. if (ar.isError()) {
  537. return ar;
  538. }
  539. }
  540. // Check:faultIds有效性
  541. {
  542. if (faultIds == null || faultIds.length == 0) {
  543. return AjaxResult.error("下发故障数据为空!");
  544. }
  545. }
  546. // 删除调试表故障数据。
  547. debugFaultService.deleteAll();
  548. //
  549. Seat seat = seatService.selectSeatBySeatId(seatId);
  550. Sim sim = getSimBySeatIdNewVer(seatId);
  551. // check sim
  552. // 打开socket
  553. {
  554. socketService.tryOpenAll();
  555. }
  556. // Step 1 主动查询一次模拟器状态。
  557. {
  558. AjaxResult arE3 = checkOneSimStateActive(seat);
  559. if (arE3.isError()) {
  560. return arE3;
  561. }
  562. }
  563. sim = simService.uniqueBySimNum(sim.getSimNum());
  564. // Step 2
  565. // msg判断,是否含有"故障部位"字符串
  566. {
  567. if (checkReplace) {
  568. AjaxResult arE2 = readOneSimAllFaultStartCheck(seat, sim);
  569. if (arE2.isError()) {
  570. return arE2;
  571. }
  572. }
  573. }
  574. // Step 3 清除对应一台模拟器 所有故障部位故障。
  575. {
  576. clearOneSimAllFaultBySim(seat, sim);
  577. }
  578. // Step 4 下发对应一台模拟器 出题选中的 故障位置故障。
  579. {
  580. Fault[] faults = new Fault[faultIds.length];
  581. for (int i = 0; i < faultIds.length; i++) {
  582. faults[i] = faultService.selectFaultByFaultId(faultIds[i]);
  583. }
  584. writeOneSimAllSelectFaultByDebug(seat, sim, faults);
  585. }
  586. // Step 5 读取
  587. {
  588. readOneSimAllFaultFirstTimeBySim(seat, sim, faultIds);
  589. }
  590. return AjaxResult.success("下发故障流程执行成功!" + SimDateUtil.getNow());
  591. }
  592. /**
  593. * debug校验seatId
  594. *
  595. * @param seatId
  596. * @return
  597. */
  598. public AjaxResult debugCheckSeatId(final Long seatId) {
  599. if (seatId == null || seatId <= 0) {
  600. return AjaxResult.error("座次信息不正确!");
  601. }
  602. Seat seat = seatService.selectSeatBySeatId(seatId);
  603. if (seat == null) {
  604. return AjaxResult.error("座次信息不存在!");
  605. }
  606. return AjaxResult.success();
  607. }
  608. /**
  609. * debug扫描所有座次模拟器
  610. *
  611. * @return
  612. */
  613. public AjaxResult debugScanAllSeat() {
  614. List<ScanSeatVo> list = new ArrayList<>();
  615. seatService.listAllEnable().forEach(seat -> {
  616. AjaxResult ar = commCheckService.checkOneSeatState(seat, true);
  617. String text = ar.get(AjaxResult.MSG_TAG).toString();
  618. // 新查询
  619. seat = seatService.selectSeatBySeatId(seat.getSeatId());
  620. // 座上sim
  621. Sim sim = simService.selectSimBySimId(seat.getCurrentSimId());
  622. if (sim != null) {
  623. list.add(new ScanSeatVo(seat.getSeatId(), sim.getSimId(), sim.getSimType(), text));
  624. } else {
  625. list.add(new ScanSeatVo(seat.getSeatId(), 0L, "", text));
  626. }
  627. });
  628. return AjaxResult.success(list);
  629. }
  630. private String[] getGZBWBySimType(String simType) {
  631. if (StringUtils.isBlank(simType)) {
  632. return new String[0];
  633. }
  634. switch (simType) {
  635. case Sim.TYPE_0001 -> {
  636. return TYPE_1_BIND_MSG;
  637. }
  638. case Sim.TYPE_0002 -> {
  639. return TYPE_2_BIND_MSG;
  640. }
  641. case Sim.TYPE_0003 -> {
  642. return TYPE_3_BIND_MSG;
  643. }
  644. default -> {
  645. return new String[0];
  646. }
  647. }
  648. }
  649. /**
  650. * 下发所有选中的真实的故障部位。
  651. *
  652. * @param re
  653. */
  654. public void writeOneSimAllSelectFaultByExam(RealExam re) {
  655. // 更新Exam状态。
  656. realExamService.updateOneState(re.getExamId(), RealExam.State.SIM_WRITING);
  657. List<RealExamFault> list = realExamFaultService.listAllType2FlagYesClearedStateByExamId(re.getExamId());
  658. for (RealExamFault ref : list) {
  659. Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
  660. Sim sim = simService.selectSimBySimId(re.getSimId());
  661. Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
  662. // 选中的故障才下发。
  663. writeOneSimOneFault(seat, sim, ref, f);
  664. }
  665. }
  666. public void writeOneSimAllSelectFaultByDebug(Seat seat, Sim sim, Fault[] faults) {
  667. for (Fault f : faults) {
  668. writeOneSimOneFault(seat, sim, null, f);
  669. }
  670. }
  671. public void writeOneSimOneFault(Seat seat, Sim sim, RealExamFault ref, Fault f) {
  672. l.info("下发故障:getSimId = {},fault.getName = {}", sim.getSimId(), f.getName());
  673. // todo:ref is null.
  674. // 下发故障
  675. SimMsg smA1 = commBuildService.buildSendMsgWriteFault(sim.getSimNum(), f.getBindHardwareMsg());
  676. SimMsg smA2 = send(smA1, seat, sim, RETRY_COUNT_WRITE_ONE_FAULT, commStrategy.getSleepLong());
  677. }
  678. /**
  679. * 一个模拟器 所有故障 开始考试前 检查读取。
  680. * 有两处引用。正式开始和调试。
  681. *
  682. * @param seat
  683. * @param sim
  684. * @return
  685. */
  686. public AjaxResult readOneSimAllFaultStartCheck(final Seat seat, final Sim sim) {
  687. // 查询某型号所有真实的故障部位。
  688. Fault q = new Fault();
  689. q.setFaultType(Fault.Type.REAL_GZBW);
  690. q.setSimType(sim.getSimType());
  691. List<Fault> listF = faultService.selectFaultList(q);
  692. // 未正确安装可换件故障List
  693. // NG not good
  694. List<FaultCheckVo> listNGVo = new ArrayList<>();
  695. // not good fault_id HashSet
  696. Set<String> setNG = new HashSet<>();
  697. // 单一故障部位检查
  698. {
  699. for (Fault oneF : listF) {
  700. FaultCheckVo voOne = new FaultCheckVo();
  701. voOne.setSeat(seat);
  702. voOne.setSim(sim);
  703. voOne.setFault(oneF);
  704. AjaxResult ar = readOneSimOneFaultStartSimpleCheck(voOne);
  705. // getDefaultErrorAR voReturn 可能为空
  706. FaultCheckVo voReturn = (FaultCheckVo) ar.get(AjaxResult.DATA_TAG);
  707. if (voReturn != null) {
  708. if (voReturn.isCheckOk()) {
  709. l.info("log 故障部位[{}][{}]安装ok;", oneF.getBindHardwareMsg(), oneF.getReplaceName());
  710. } else {
  711. l.info("log 故障部位[{}][{}]未正确安装;", oneF.getBindHardwareMsg(), oneF.getReplaceName());
  712. listNGVo.add(voReturn);
  713. setNG.add(oneF.getFaultId());
  714. }
  715. }
  716. // 得出ar有问题直接返回,不执行后面检查。
  717. if (ar.isError()) {
  718. return ar;
  719. }
  720. }
  721. }
  722. // 复核条件检查
  723. {
  724. AjaxResult ar = readOneSimAllFaultStartGlobalCheck(sim, setNG);
  725. if (ar.isError()) {
  726. return ar;
  727. }
  728. }
  729. //
  730. if (!listNGVo.isEmpty()) {
  731. StringBuilder sb = new StringBuilder();
  732. for (FaultCheckVo oneVo : listNGVo) {
  733. sb.append(oneVo.getErrorMsg());
  734. }
  735. sb.append("请正确安装可换件,检查后重新开始!");
  736. return AjaxResult.error(sb.toString());
  737. }
  738. return AjaxResult.success("所有故障部位检查没有问题。");
  739. }
  740. private String buildKeyType0003(String bindHardwareMsg) {
  741. return buildKey(Sim.TYPE_0003, bindHardwareMsg);
  742. }
  743. private String buildKey(String simType, String bindHardwareMsg) {
  744. if (StringUtils.isAnyBlank(simType, bindHardwareMsg)) {
  745. throw new IllegalArgumentException("isAnyBlank");
  746. }
  747. return simType + "@" + bindHardwareMsg;
  748. }
  749. /**
  750. * 一个模拟器 全部故障 开始考试前 复合读取检查。
  751. *
  752. * @param sim
  753. * @param setNG
  754. * @return
  755. */
  756. public AjaxResult readOneSimAllFaultStartGlobalCheck(Sim sim, Set<String> setNG) {
  757. if (Objects.isNull(setNG) || setNG.isEmpty()) {
  758. return AjaxResult.success("");
  759. }
  760. if (StringUtils.equals(sim.getSimType(), Sim.TYPE_0003)) {
  761. // if (map.containsKey(buildKeyType0003("01"))) {
  762. // SimMsg smR = map.get(buildKeyType0003("01")).getSimMsgReceive();
  763. // String smRS = CommParseUtils.subContentData(smR);
  764. // // 没有连接FFC排线
  765. // if (StringUtils.endsWith(smRS, "02")) {
  766. // return AjaxResult.error("请检查FFC排线连接!");
  767. // } else if (StringUtils.endsWith(smRS, "01")) {
  768. //
  769. // }
  770. // }
  771. if (setNG.contains(FaultIdConst.T0003.F03) &&
  772. setNG.contains(FaultIdConst.T0003.F04) &&
  773. setNG.contains(FaultIdConst.T0003.F0B) &&
  774. setNG.contains(FaultIdConst.T0003.F0E)
  775. ) {
  776. return AjaxResult.error("请检查 显控报警板与主板连接线 连接情况!");
  777. }
  778. }
  779. return AjaxResult.success("复合读取检查 成功。");
  780. }
  781. /**
  782. * 一个模拟器 一个故障 开始考试前 简单读取检查。
  783. *
  784. * @param vo
  785. * @return
  786. */
  787. public AjaxResult readOneSimOneFaultStartSimpleCheck(FaultCheckVo vo) {
  788. l.info("readOneSimOneFaultCheck vo = {}", vo);
  789. SimMsg smS = commBuildService.buildSendMsgReadFaultResistance(vo.getSim().getSimNum(), vo.getFault().getBindHardwareMsg());
  790. SimMsg smR = send(smS, vo.getSeat(), vo.getSim(), RETRY_COUNT_CHECK_ONE_FAULT, commStrategy.getSleepLong());
  791. if (smR.isResultNotOk()) {
  792. if (Objects.equals(smR.getResult(), SimMsg.Result.RECEIVE_CHECK_FAIL) ||
  793. (Objects.equals(smR.getResult(), SimMsg.Result.RECEIVE_NOT_MATCH))) {
  794. l.info("reset connection!");
  795. String ip = vo.getSeat().getSeatRs485Ip();
  796. Integer port = vo.getSeat().getSeatRs485Port();
  797. SimSocketParamVo sspv = new SimSocketParamVo(ip, port);
  798. socketService.closeOne(sspv, true);
  799. }
  800. return smR.getDefaultErrorAR();
  801. }
  802. // set send and receive msg.
  803. vo.setSimMsgSend(smS);
  804. vo.setSimMsgReceive(smR);
  805. return simReceiveService.getOneFaultCheck(vo);
  806. }
  807. /**
  808. * 第一次读取,作为出题值。
  809. *
  810. * @param re
  811. */
  812. public void readOneSimAllFaultFirstTimeByExam(RealExam re) {
  813. l.info("readOneSimAllFaultFirstTimeByExam re = {}", re);
  814. List<RealExamFault> list = realExamFaultService.listAllType2(re.getExamId());
  815. for (RealExamFault ref : list) {
  816. Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
  817. Sim sim = simService.selectSimBySimId(re.getSimId());
  818. Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
  819. readOneSimOneFaultFirstTime(seat, sim, ref, f, null);
  820. }
  821. }
  822. /**
  823. * 第一次读取,作为出题值。debug模式。
  824. *
  825. * @param seat
  826. * @param sim
  827. * @param faultIds debug模式必须有值
  828. */
  829. public void readOneSimAllFaultFirstTimeBySim(Seat seat, Sim sim, final String[] faultIds) {
  830. l.info("readOneSimAllFaultFirstTimeBySim s = {}", sim);
  831. List<Fault> list = faultService.listType3(sim.getSimType());
  832. for (Fault f : list) {
  833. readOneSimOneFaultFirstTime(seat, sim, null, f, faultIds);
  834. }
  835. }
  836. /**
  837. * 第一次读取,作为出题值。
  838. *
  839. * @param sim
  840. * @param ref debug调试模式为空。可以为空。
  841. * @param fault
  842. * @param faultIds debug模式必须有值
  843. */
  844. public void readOneSimOneFaultFirstTime(Seat seat, Sim sim, RealExamFault ref, Fault fault, String[] faultIds) {
  845. l.info("readOneSimOneFaultFirstTime");
  846. // 读取一次当前电阻代表值作为出题值。
  847. SimMsg smS = commBuildService.buildSendMsgReadFaultResistance(sim.getSimNum(), fault.getBindHardwareMsg());
  848. SimMsg smR = send(smS, seat, sim, RETRY_COUNT_WRITE_ONE_FAULT, commStrategy.getSleepLong());
  849. simReceiveService.setFaultQuestionValue(smR, sim, ref, fault, faultIds);
  850. }
  851. /**
  852. * debug读取一个故障位置数据
  853. *
  854. * @param seatId
  855. * @param bindHardwareMsg
  856. * @return
  857. */
  858. public SimMsg debugReadOneFaultResistance(final Long seatId, final String bindHardwareMsg) {
  859. Seat seat = seatService.selectSeatBySeatId(seatId);
  860. Sim sim = getSimBySeatIdNewVer(seatId);
  861. SimMsg sm = commBuildService.buildSendMsgReadFaultResistance(sim.getSimNum(), bindHardwareMsg);
  862. return send(sm, seat, null, RETRY_COUNT_0, commStrategy.getSleepShort());
  863. }
  864. /**
  865. * debug读取全部故障位置数据
  866. *
  867. * @param seatId
  868. * @return
  869. */
  870. public List<SimMsg> debugReadAllFaultResistance(final Long seatId) {
  871. Sim sim = getSimBySeatIdNewVer(seatId);
  872. List<SimMsg> list = new ArrayList<>();
  873. String simType = simService.uniqueBySimNum(sim.getSimNum()).getSimType();
  874. for (String b : getGZBWBySimType(simType)) {
  875. list.add(debugReadOneFaultResistance(seatId, b));
  876. }
  877. return list;
  878. }
  879. /**
  880. * 读取一个模拟器的一个故障点位的值。
  881. *
  882. * @param sim
  883. * @param reF
  884. * @param fault
  885. * @param refState 修改的目标状态。debug模式下执行为null。
  886. */
  887. public void readOneSimOneFaultResistance(Seat seat, Sim sim, RealExamFault reF, Fault fault, final String refState) {
  888. l.info("readOneSimOneFaultResistance");
  889. SimMsg smS = commBuildService.buildSendMsgReadFaultResistance(sim.getSimNum(), fault.getBindHardwareMsg());
  890. SimMsg sm2 = null;
  891. if (reF != null && refState != null) {
  892. if (StringUtils.equals(refState, RealExamFault.State.LOOP_READ)) { // 是否是中间读取
  893. sm2 = send(smS, seat, sim, RETRY_COUNT_READ_ONE_RESISTANCE_MIDDLE, commStrategy.getSleepShort(), false);
  894. } else if (StringUtils.equals(refState, RealExamFault.State.FINISH)) { // 是否最后一次读取。
  895. sm2 = send(smS, seat, sim, RETRY_COUNT_READ_ONE_RESISTANCE_FINAL, commStrategy.getSleepShort());
  896. } else {
  897. sm2 = send(smS, seat, sim, RETRY_COUNT_0, commStrategy.getSleepShort());
  898. }
  899. } else {
  900. sm2 = send(smS, seat, sim, RETRY_COUNT_READ_ONE_RESISTANCE_FINAL, commStrategy.getSleepShort());
  901. }
  902. simReceiveService.setFaultAnswerValue(sm2, sim, reF, fault, refState);
  903. }
  904. public SimMsg send(final SimMsg sm, final Seat seat, final Sim sim, final int retryTotalCount, final long sleep) {
  905. return send(sm, seat, sim, retryTotalCount, sleep, true);
  906. }
  907. /**
  908. * 最基本的通信方法。
  909. * send hex message
  910. * <p>
  911. * 去掉synchronized
  912. *
  913. * @param sm 发送
  914. * @param seat 不能为空
  915. * @param sim 可以为空!更新最后发送/接收时间 用。
  916. * @param retryTotalCount 重试次数
  917. * @param sleep 不使用传入0,不进行挂起。
  918. * @param importantTask 是否是重要的。
  919. * @return
  920. */
  921. public SimMsg send(final SimMsg sm, final Seat seat, final Sim sim, final int retryTotalCount, final long sleep, final boolean importantTask) {
  922. if (!config.isCommGlobal()) {
  923. l.warn("isCommGlobal == false [模拟器通信被禁用!]");
  924. return sm;
  925. }
  926. if (sm == null || sm.getSendMsg() == null || StringUtils.isBlank(sm.getSendMsg())) {
  927. throw new IllegalArgumentException("SimMsg IllegalArgument");
  928. }
  929. // sim
  930. if (seat == null) {
  931. throw new IllegalArgumentException("seat is null");
  932. }
  933. if (sleep < 0) {
  934. throw new IllegalArgumentException("SimMsg sleep");
  935. }
  936. // log.
  937. {
  938. l.info("####发送#### == Seat[{}],SimMsg[{}]", seat, sm);
  939. }
  940. SimSocketParamVo sspv = seat.toSimSocketParamVo();
  941. try {
  942. // 如果没有打开socket,顺道打开。正好后面要sleep。
  943. // 不强制重开Socket。
  944. // 先进行Socket相关处理。
  945. // 优先级高的在运行,跳过
  946. if (importantTask == false && socketService.getImportantTaskRunning(sspv)) {
  947. sm.setResult(SimMsg.Result.SKIP);
  948. socketService.setImportantTaskRunning(sspv, false);
  949. l.warn("####跳过运行#### sm = {}", sm);
  950. return sm;
  951. }
  952. if (importantTask) {
  953. socketService.setImportantTaskRunning(sspv, true);
  954. }
  955. socketService.openOne(sspv);
  956. // Socket情况不正确,直接返回。
  957. if (socketService.isNotOk(sspv)) {
  958. sm.setResult(SimMsg.Result.SOCKET_CONNECT_EXCEPTION);
  959. socketService.setImportantTaskRunning(sspv, false);
  960. return sm;
  961. }
  962. {
  963. // sleep挂起线程,追求顺序请求。
  964. // 大于0才挂起。
  965. if (sleep > 0 && socketService.getVo(sspv).getPreviousSendSleep() > 0L) {
  966. // 时间间隔挂起。
  967. Thread.sleep(socketService.getVo(sspv).getPreviousSendSleep());
  968. }
  969. }
  970. socketService.getVo(sspv).setPreviousSendSleep(sleep);
  971. Socket socket = socketService.getVo(sspv).getSocket();
  972. InputStream is = socket.getInputStream();
  973. OutputStream os = socket.getOutputStream();
  974. Sim simSeat = simService.selectSimBySimId(seat.getCurrentSimId());
  975. socket.setSoTimeout(commStrategy.getSoTimeout(simSeat));
  976. os.write(hexStrToByteArrs(sm.getSendMsg()));
  977. sm.setSendTime(DateUtils.getNowDate());
  978. if (sim != null) {
  979. simService.updateLastSentTime(sim);
  980. }
  981. byte[] buffer = new byte[LENGTH_24];
  982. int length = is.read(buffer);
  983. StringBuilder sbHex = new StringBuilder();
  984. for (int i = 0; i < length; i++) {
  985. sbHex.append(String.format("%02X", buffer[i]));
  986. }
  987. String receiveWith0 = sbHex.toString();
  988. // 原始带0的收到报文。
  989. sm.setReceiveOriginalMsg(receiveWith0);
  990. sm.setReceiveMsg(commReceiveService.removeRrdfix0(receiveWith0));
  991. sm.setReceiveTime(DateUtils.getNowDate());
  992. // log.
  993. {
  994. AjaxResult ar = commReceiveService.checkReceiveMsgFormat(sm.getReceiveMsg());
  995. if (ar.isError()) {
  996. // todo:
  997. l.warn("####接收错误@格式错误#### = sm = {},ar = {}", sm, ar);
  998. sm.setResult(SimMsg.Result.RECEIVE_CHECK_FAIL);
  999. socketService.setImportantTaskRunning(sspv, false);
  1000. return sm;
  1001. }
  1002. }
  1003. {
  1004. AjaxResult ar = commReceiveService.checkReceiveMsgMatch(sm);
  1005. if (ar.isError()) {
  1006. l.warn("####接收错误@匹配错误#### sm = {},ar = {}", sm, ar);
  1007. sm.setResult(SimMsg.Result.RECEIVE_NOT_MATCH);
  1008. socketService.setImportantTaskRunning(sspv, false);
  1009. return sm;
  1010. }
  1011. }
  1012. l.info("####接收成功#### = {}", sm);
  1013. if (sim != null) {
  1014. simService.updateLastReceivedTime(sim);
  1015. }
  1016. sm.setResult(SimMsg.Result.SUCCESS);
  1017. socketService.setImportantTaskRunning(sspv, false);
  1018. // 最后返回报文实体。
  1019. return sm;
  1020. } catch (InterruptedException | IOException e) {
  1021. // SocketTimeoutException
  1022. l.error("SocketTimeoutException");
  1023. e.printStackTrace();
  1024. sm.setResult(SimMsg.Result.READ_TIMEOUT_EXCEPTION);
  1025. socketService.setImportantTaskRunning(sspv, false);
  1026. if (sim != null) {
  1027. l.info("fail sim.getSimId() = {}", sim.getSimId());
  1028. }
  1029. // Socket失败计数
  1030. socketService.failedPlus1(sspv);
  1031. if (socketService.failedIsReachedMax(sspv, SocketService.SOCKET_CONNECT_RETRY_COUNT_LIMIT)) {
  1032. // 达到重试次数上限,认为模拟器离线
  1033. if (sim != null) {
  1034. simService.updateSimStateBySimId(sim.getSimId(), Sim.State.OFFLINE);
  1035. }
  1036. socketService.failedReset0(sspv);
  1037. }
  1038. // 先考虑一台模拟器演示。
  1039. // 进行重试 start
  1040. if (sm.getRetryCount() == RETRY_COUNT_0) {
  1041. l.warn("####RetryTotalCount不重试RETRY_COUNT_0#### = getSimMsgId = {}", sm.getSimMsgId());
  1042. return sm;
  1043. }
  1044. if (sm.getRetryCount() < retryTotalCount) {
  1045. sm.retryCountPlus1();
  1046. send(sm, seat, sim, retryTotalCount, sleep);
  1047. l.warn("####RetryTotalCount重试#### = {}", sm);
  1048. } else {
  1049. l.warn("####RetryTotalCount达到重试上限#### = {}", sm);
  1050. }
  1051. // 进行重试 end
  1052. // 最后返回报文实体。
  1053. return sm;
  1054. }
  1055. }
  1056. /**
  1057. * todo:
  1058. *
  1059. * @param sm
  1060. * @param s
  1061. * @param retryTotalCount
  1062. * @param sleep
  1063. * @return
  1064. */
  1065. public SimMsg sendRetry(final SimMsg sm, final Sim s, final int retryTotalCount, final long sleep) {
  1066. return null;
  1067. }
  1068. /**
  1069. * https://mvnrepository.com/artifact/com.infiniteautomation/modbus4j/3.0.3
  1070. */
  1071. public void test02() {
  1072. byte[] data = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02}; // 示例数据
  1073. // int crc = ModbusUtils.calculateCRC(data);
  1074. // System.out.println("CRC-16/MODBUS 校验值: " + Integer.toHexString(crc));
  1075. }
  1076. public static byte[] hexStrToByteArrs(String hexString) {
  1077. // if (StringUtils.isEmpty(hexString)) {
  1078. // return null;
  1079. // }
  1080. hexString = hexString.replaceAll(" ", "");
  1081. int len = hexString.length();
  1082. int index = 0;
  1083. byte[] bytes = new byte[len / 2];
  1084. while (index < len) {
  1085. String sub = hexString.substring(index, index + 2);
  1086. bytes[index / 2] = (byte) Integer.parseInt(sub, 16);
  1087. index += 2;
  1088. }
  1089. return bytes;
  1090. }
  1091. public String logBytesToString(byte[] bytes) {
  1092. if (bytes == null || bytes.length == 0) {
  1093. return "";
  1094. }
  1095. StringBuffer sbHex = new StringBuffer();
  1096. byte[] buffer = new byte[bytes.length];
  1097. for (int i = 0; i < bytes.length; i++) {
  1098. sbHex.append(String.format("%02X", buffer[i]));
  1099. }
  1100. return sbHex.toString();
  1101. }
  1102. public static String bytesToHexV2(byte[] bytes) {
  1103. StringBuilder hexString = new StringBuilder();
  1104. for (byte b : bytes) {
  1105. String hex = Integer.toHexString(0xFF & b); // 将字节转换为十六进制字符串
  1106. if (hex.length() == 1) {
  1107. hexString.append('0'); // 如果是单个字符,补零
  1108. }
  1109. hexString.append(hex);
  1110. }
  1111. return hexString.toString();
  1112. }
  1113. /**
  1114. * checkOneSeatState 包装调用。
  1115. * seatId映射到Sim对象。
  1116. *
  1117. * @param seatId
  1118. * @return 可能为空
  1119. */
  1120. public Sim getSimBySeatIdNewVer(Long seatId) {
  1121. Seat seat = seatService.selectSeatBySeatId(seatId);
  1122. // 执行在线监测。
  1123. AjaxResult ar = commCheckService.checkOneSeatState(seat, true);
  1124. if (ar != null) {
  1125. return (Sim) ar.get(AjaxResult.DATA_TAG);
  1126. } else {
  1127. return null;
  1128. }
  1129. }
  1130. /**
  1131. * todo:
  1132. *
  1133. * @return
  1134. */
  1135. public AjaxResult debugResetAnything() {
  1136. // Step:关闭所有Socket连接
  1137. socketService.closeAll();
  1138. // Step:ping路由器,返回在线情况。
  1139. // Step:ping教员端主机,返回在线情况。
  1140. // Step:ping所有学员端主机,返回在线情况列表。
  1141. // Step:ping所有RS485,返回在线情况列表。
  1142. // Step:建立所有模拟器Socket,返回情况列表。
  1143. // Step:有Socket的前提下,尝试查询所有模拟器连接情况,得到连接的模拟器 型号、序列号信息
  1144. // Step:所有连接的模拟器,清除每一个模拟器的各个故障
  1145. // Step:所有连接的模拟器,读取每一个模拟器的各个故障,是否处于考试准备ok状态
  1146. // 删除debug表中所有数据。
  1147. debugFaultService.deleteAll();
  1148. return AjaxResult.success("全部重置成功。" + SimDateUtil.getNow());
  1149. }
  1150. /**
  1151. * 每30s执行一次。
  1152. */
  1153. public void scheduledChargingCount() {
  1154. // 查询到唯一打开的 考试 或 训练
  1155. RealExamCollection rec = realExamCollectionService.selectRealExamCollectionOpenedNotSelfExercise();
  1156. //
  1157. if (rec == null) {
  1158. l.info("rec == null!");
  1159. return;
  1160. }
  1161. Long recId = rec.getExamCollectionId();
  1162. RealExam q = new RealExam();
  1163. q.setExamCollectionId(recId);
  1164. // 只需要0002型模拟器。
  1165. q.setSimType(Sim.TYPE_0002);
  1166. List<RealExam> list = realExamService.selectRealExamList(q);
  1167. if (list == null || list.isEmpty()) {
  1168. return;
  1169. }
  1170. list.forEach((RealExam re) -> {
  1171. if (re == null || re.getExamId() == null || re.getExamId() == 0L) {
  1172. return;
  1173. }
  1174. if (StringUtils.equals(re.getExamStatus(), RealExam.State.LOGGED_IN)) {
  1175. Seat qSeat = seatService.selectSeatBySeatId(re.getSeatId());
  1176. // 检查后就知道seat上是否有sim
  1177. AjaxResult ar = commCheckService.checkOneSeatState(qSeat, true);
  1178. if (ar.isSuccess()) {
  1179. // 获取当前simId
  1180. Long currSimId = seatService.selectSeatBySeatId(re.getSeatId()).getCurrentSimId();
  1181. if (!currSimId.equals(Sim.ID_0)) {
  1182. Integer count = simService.updateChargingCountPlusBySimId(currSimId);
  1183. l.info("scheduledChargingCount count = {}", count);
  1184. } else {
  1185. l.info("scheduledChargingCount Sim.ID_0 seatId = {}", qSeat.getSeatId());
  1186. }
  1187. } else {
  1188. l.info("checkOneSeatState failed");
  1189. }
  1190. } else {
  1191. l.info("skip");
  1192. }
  1193. });
  1194. }
  1195. }