1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291 |
- package com.ruoyi.sim.service.impl;
- import com.ruoyi.common.core.domain.AjaxResult;
- import com.ruoyi.common.utils.DateUtils;
- import com.ruoyi.sim.config.SimConfig;
- import com.ruoyi.sim.constant.CommConst;
- import com.ruoyi.sim.constant.FaultIdConst;
- import com.ruoyi.sim.domain.*;
- import com.ruoyi.sim.domain.vo.FaultCheckVo;
- import com.ruoyi.sim.domain.vo.ScanSeatVo;
- import com.ruoyi.sim.domain.vo.SimSocketParamVo;
- import com.ruoyi.sim.util.SimDateUtil;
- import org.apache.commons.collections4.SetUtils;
- import org.apache.commons.lang3.StringUtils;
- import org.slf4j.LoggerFactory;
- import org.slf4j.Logger;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.scheduling.annotation.Async;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.Socket;
- import java.util.*;
- import static com.ruoyi.sim.constant.CommConst.*;
- /**
- * 硬件通信
- * send service.
- * "commSendService"
- */
- @Service
- public class CommSendService {
- private static final Logger l = LoggerFactory.getLogger(CommSendService.class);
- @Autowired
- private CommReceiveService simReceiveService;
- @Autowired
- private SeatService seatService;
- @Autowired
- private SimService simService;
- @Autowired
- private FaultService faultService;
- @Autowired
- private RealExamService realExamService;
- @Autowired
- private RealExamFaultService realExamFaultService;
- @Autowired
- private RealExamCollectionService realExamCollectionService;
- @Autowired
- private CommBuildService commBuildService;
- @Autowired
- private DebugFaultService debugFaultService;
- @Autowired
- private SocketService socketService;
- @Autowired
- private CommCheckService commCheckService;
- @Autowired
- private CommReceiveService commReceiveService;
- @Autowired
- private SimConfig config;
- @Autowired
- private CommStrategy commStrategy;
- @Autowired
- private CmdService cmdService;
- /**
- * 定时任务。
- */
- public void scheduledLoopRead() {
- readAll();
- }
- public void readAll() {
- l.info("readAll");
- List<RealExam> listRe = realExamService.listAllByStatus(RealExam.State.ANSWERING);
- listRe.forEach(e -> {
- if (e == null) {
- return;
- }
- List<RealExamFault> listRef = realExamFaultService.listAllType2State2and3ByExamId(e.getExamId());
- listRef.forEach(ref -> {
- RealExam re = realExamService.selectRealExamByExamId(ref.getExamId());
- Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
- Sim sim = simService.selectSimBySimId(e.getSimId());
- Fault fault = faultService.selectFaultByFaultId(ref.getFaultId());
- if (fault != null && Fault.Type.REAL_GZBW.equals(fault.getFaultType()) && Fault.State.ENABLE.equals(fault.getFaultState())) {
- readOneSimOneFaultResistance(seat, sim, ref, fault, null);
- }
- });
- });
- }
- /**
- * Async version.
- */
- @Async("tp-comm")
- public void readAllAsync() {
- readAll();
- }
- /**
- * 开始考试以后,交卷之前,定时任务中间读取值,作为答题值。有优先级高的任务可能跳过执行。
- *
- * @param re
- */
- public void readOneExamAtMiddle(RealExam re) {
- l.info("readOneExamAtMiddle getExamId = {}", re.getExamId());
- List<RealExamFault> list = realExamFaultService.listAllType2State2and3ByExamId(re.getExamId());
- for (RealExamFault ref : list) {
- {
- RealExamFault refQ = realExamFaultService.selectRealExamFaultByRefId(ref.getRefId());
- if (refQ == null || refQ.getExamId() == 0L) {
- continue;
- }
- if (!RealExamFault.State.WRITTEN.equals(ref.getRefState()) && !RealExamFault.State.LOOP_READ.equals(ref.getRefState())) {
- continue;
- }
- }
- Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
- Sim sim = simService.selectSimBySimId(re.getSimId());
- Fault fault = faultService.selectFaultByFaultId(ref.getFaultId());
- readOneSimOneFaultResistance(seat, sim, ref, fault, RealExamFault.State.LOOP_READ);
- }
- }
- /**
- * 交卷最后读取值,作为答题值。
- *
- * @param re
- */
- public void readOneExamAtLast(RealExam re) {
- l.info("readOneExamAtLast getExamId = {}", re.getExamId());
- List<RealExamFault> list = realExamFaultService.listAllType2State2and3ByExamId(re.getExamId());
- for (RealExamFault ref : list) {
- Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
- Sim sim = simService.selectSimBySimId(re.getSimId());
- Fault fault = faultService.selectFaultByFaultId(ref.getFaultId());
- readOneSimOneFaultResistance(seat, sim, ref, fault, RealExamFault.State.FINISH);
- }
- // 计算扣分。
- // 最后都读取到,才算扣分。
- {
- // todo:暂时不算。
- // calculateScore(re.getExamId());
- }
- }
- public void readOneSimAtLastByDebug(Seat seat, Sim sim) {
- l.info("readOneSimAtLastByDebug");
- List<Fault> list = faultService.listType3(sim.getSimType());
- for (Fault fault : list) {
- readOneSimOneFaultResistance(seat, sim, null, fault, null);
- }
- }
- public AjaxResult debugReadAllFaultResistanceBySimNum(final Long seatId) {
- // check
- if (seatId == null || seatId == 0L) {
- return AjaxResult.error("尚未选择座次。");
- }
- //
- // 打开socket
- {
- socketService.tryOpenAll();
- }
- //
- Seat seat = seatService.selectSeatBySeatId(seatId);
- Sim sim = getSimBySeatIdNewVer(seatId);
- {
- AjaxResult arE3 = checkOneSimStateActive(seat);
- if (arE3.isError()) {
- return arE3;
- }
- }
- sim = simService.uniqueBySimNum(sim.getSimNum());
- // todo: aj改造
- readOneSimAtLastByDebug(seat, sim);
- return AjaxResult.success("成功读取!");
- }
- @Async("tp-comm")
- public void readOneExamAtLastAsync(RealExam re) {
- l.info("readOneExamAtLastAsync");
- readOneExamAtLast(re);
- }
- /**
- * 计算减分(不包括超时)。汇总到deduction_total_score字段。
- *
- * @param realExamId
- */
- public void calculateScore(Long realExamId) {
- realExamService.updateOneState(realExamId, RealExam.State.CALCULATING_SCORE);
- int minus = 0;
- // 排除故障部分 + 维修报告选择部分
- realExamFaultService.calculateMinusByRealExamId(realExamId);
- // 超时部分
- int timeoutMinute = 0;
- //
- realExamService.updateOneState(realExamId, RealExam.State.GOT_REPORT);
- }
- /**
- * todo:????
- * 定时任务。
- */
- public void scheduledReadSim() {
- l.info("scheduledReadSim");
- if (!realExamCollectionService.existAtLeastOneOpened()) {
- l.info("没有open的考试集合");
- return;
- }
- readAll();
- //
- // AA010102010000000055
- // AA010102010000000055
- String simNum = "01";
- String simType = "0002";
- // for (int i = 0; i < 3; i++) {
- // debugReadSimType(simNum);
- // }
- // debugClearAllFault(simNum, simType);
- // debugWriteAllFault(simNum, simType);
- // for (int i = 0; i < 3; i++) {
- // debugReadAllFaultResistance(simNum, simType);
- // }
- // debugClearOneFault(simNum, "02");
- // boolean bRea = isReachable("123.112.16.165");
- // debugReadSimType(simNum);
- // l.info("bRea:" + bRea);
- // debugReadAllFaultResistance(simNum, simType);
- // debugWriteAllFault(simNum, simType);
- // for (int i = 0; i < 5; i++) {
- // debugReadAllFaultResistance(simNum, simType);
- // }
- // if (isSocketOk()) {
- // readAllAsync();
- // } else {
- // scheduledConnect();
- // }
- }
- /**
- * 连接情况 的 定时任务。
- * 执行频率: 5min
- */
- public void scheduledConnect() {
- l.info("scheduled####Connect 连接情况 的 定时任务");
- // if (!SimDebugConfig.SCHEDULED_CONNECT) {
- if (true) {
- l.info("连接情况 的 定时任务被禁用!");
- return;
- }
- // 暂时注释
- // if (!realExamCollectionService.existAtLeastOneOpened()) {
- // l.info("没有open的任何集合");
- // return;
- // }
- //
- {
- AjaxResult ar = commCheckService.checkRouterState(config.getRouterIp());
- if (ar.isError()) {
- return;
- }
- }
- //
- {
- seatService.listAllRs485Ip().forEach(rs485Ip -> {
- commCheckService.checkPingRs485State(rs485Ip);
- });
- }
- // SocketOldService实现
- // if (socketOldService.isCachedSocketOk()) {
- // checkAllSeatAndSimState();
- // }
- socketService.tryOpenAll();
- commCheckService.checkAllSeatAndSimState();
- }
- /**
- * 每天06:00/12:00/18:00/00:00执行
- */
- public void scheduledCloseAllSocket() {
- l.info("scheduledCloseAllSocket");
- AjaxResult ar = socketService.closeAll();
- l.info("AjaxResult = {}", ar);
- }
- /**
- * 每30min运行一次。
- */
- public void scheduledSystemAutoCleanExam() {
- l.info("scheduledSystemAutoCleanExam");
- realExamService.systemAutoCleanExam();
- }
- /**
- * 每6hour运行一次。
- */
- public void scheduledProjectRestart() {
- l.info("scheduledProjectRestart");
- cmdService.restart();
- }
- /**
- * 主动更新模拟器状态。
- * <p>
- * <p>
- * 主动查询一次模拟器状态。更新模拟器在线/离线状态;否则返回对应错误。
- * todo:需要重新考虑,不再使用。
- *
- * @param seat
- * @return
- */
- @Deprecated
- public AjaxResult checkOneSimStateActive(Seat seat) {
- // 这句可能会调整模拟器状态,后面需要重新查询。
- commCheckService.checkOneSeatState(seat, true);
- AjaxResult ar1 = commCheckService.checkOneSimOnlineState(seat, true);
- if (ar1.isError()) {
- return ar1;
- }
- // 重新最新模拟器。
- Sim sim = getSimBySeatIdNewVer(seat.getSeatId());
- // 如果模拟器离线
- if (sim != null && Sim.State.ONLINE.equals(sim.getSimState())) {
- return AjaxResult.success();
- } else {
- return AjaxResult.error("未连接模拟器,请检查连接!");
- }
- }
- @Async("tp-comm")
- public void checkAllSimStateAsync() {
- commCheckService.checkAllSeatAndSimState();
- }
- /**
- * 清除一个考试的,对应的某型号一台模拟器的,所有故障部位。
- *
- * @param re
- */
- public void clearOneSimAllFaultByExam(RealExam re) {
- l.info("clearOneSimAllFaultByExam = {}", re);
- // check
- // 更新Exam状态。
- {
- realExamService.updateOneState(re.getExamId(), RealExam.State.SIM_WRITING);
- }
- //
- List<RealExamFault> list = realExamFaultService.listAllType2InitStateByExamId(re.getExamId());
- if (list != null) {
- l.info("清除exam list = {}", list.size());
- }
- assert list != null;
- Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
- list.forEach(ref -> {
- Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
- if (faultService.isDisable(f.getFaultId())) {
- l.warn("故障 {} -被禁用", f.getName());
- throw new IllegalArgumentException("故障被禁用");
- }
- Sim sim = simService.selectSimBySimId(re.getSimId());
- // check
- //
- clearOneSimOneFault(seat, sim, ref, f);
- });
- }
- public void clearOneSimAllFaultBySim(Seat seat, Sim sim) {
- l.info("clearOneSimAllFaultBySim = {}", sim);
- faultService.listType3EnableBySimType(sim.getSimType()).forEach(f -> {
- clearOneSimOneFault(seat, sim, null, f);
- });
- }
- /**
- * Async version.
- *
- * @param re
- */
- @Async("tp-comm")
- public void clearListFaultByRealExamAsync(RealExam re) {
- clearOneSimAllFaultByExam(re);
- }
- public void clearAll() {
- // todo:
- // 根据Seat数据遍历
- seatService.listAllEnable().forEach(seat -> {
- Sim sim = getSimBySeatIdNewVer(seat.getSeatId());
- String simType = sim.getSimType();
- List<Fault> listF = faultService.listType3EnableBySimType(simType);
- listF.forEach(f -> {
- clearOneSimOneFault(seat, sim, null, f);
- });
- });
- }
- /**
- * debug读取模拟器类型序列号
- *
- * @param seatId
- * @return
- */
- public SimMsg debugReadSimType(final Long seatId) {
- Seat seat = seatService.selectSeatBySeatId(seatId);
- Sim sim = getSimBySeatIdNewVer(seatId);
- SimMsg sm = commBuildService.buildSendMsgReadSimType(sim.getSimNum());
- return send(sm, seat, sim, CommConst.RETRY_COUNT_0, commStrategy.getSleepShort());
- }
- /**
- * debug清除一个故障
- *
- * @param seatId
- * @param bindHardwareMsg
- * @return
- */
- public SimMsg debugClearOneFault(final Long seatId, final String bindHardwareMsg) {
- Seat seat = seatService.selectSeatBySeatId(seatId);
- // Sim sim = getSimBySeatIdNewVer(seatId);
- // 不需要重复调用 getSimBySeatIdNewVer。
- Sim sim = simService.selectSimBySimId(seat.getCurrentSimId());
- SimMsg sm = commBuildService.buildSendMsgClearFault(sim.getSimNum(), bindHardwareMsg);
- return send(sm, seat, sim, RETRY_COUNT_CLEAR_ONE_FAULT, commStrategy.getSleepLong());
- }
- /**
- * debug清除所有座次上的模拟器的所有故障
- *
- * @return
- */
- public AjaxResult debugClearAllSeatAllFault() {
- debugFaultService.deleteAll();
- List<Seat> list = seatService.listAllEnable();
- for (Seat seat : list) {
- if (seat == null) {
- AjaxResult.error("座次数据异常!");
- }
- //
- commCheckService.checkOneSeatState(seat, true);
- // 重新查询
- seat = seatService.selectSeatBySeatId(seat.getSeatId());
- if (seat.getCurrentSimId() == null || seat.getCurrentSimId() == 0L) {
- continue;
- }
- AjaxResult ar = debugClearAllFaultBySeatId(seat.getSeatId());
- if (ar.isError()) {
- return ar;
- }
- }
- return AjaxResult.success("清除成功,清除所有座次正确连接的模拟器的,所有的故障!" + SimDateUtil.getNow());
- }
- /**
- * debug清除SeatId上模拟器所有故障
- *
- * @param seatId
- * @return
- */
- public AjaxResult debugClearAllFaultBySeatId(final Long seatId) {
- {
- AjaxResult ar = debugCheckSeatId(seatId);
- if (ar.isError()) {
- return ar;
- }
- }
- debugFaultService.deleteAll();
- Seat seat = seatService.selectSeatBySeatId(seatId);
- Sim sim = getSimBySeatIdNewVer(seatId);
- if (sim == null) {
- return AjaxResult.error("清除失败,模拟器不存在!请检查模拟器线缆连接,模拟器线缆开关!");
- }
- sim = simService.selectSimBySimId(sim.getSimId());
- if (!Sim.State.ONLINE.equals(sim.getSimState())) {
- return AjaxResult.error("清除失败,模拟器尚未在线!");
- }
- List<SimMsg> list = new ArrayList<>();
- for (String b : getGZBWBySimType(sim.getSimType())) {
- SimMsg sm = debugClearOneFault(seatId, b);
- if (sm != null && !Objects.equals(sm.getResult(), SimMsg.Result.SUCCESS)) {
- AjaxResult.error("清除失败!");
- }
- list.add(sm);
- }
- return AjaxResult.success("清除成功,清除当前模拟器所有的故障!" + SimDateUtil.getNow());
- }
- /**
- * @param sim
- * @param reF 可以为空,表示不关联考试的,单独执行的。调试模式下为空。
- * @param f
- */
- public void clearOneSimOneFault(Seat seat, Sim sim, RealExamFault reF, Fault f) {
- l.info("clearOneSimOneFault 清除One故障:getSimNum = {},getBindHardwareMsg = {},fault.getName = {}", sim.getSimNum(), f.getBindHardwareMsg(), f.getName());
- // check todo:
- // step1
- SimMsg smS = commBuildService.buildSendMsgClearFault(sim.getSimNum(), f.getBindHardwareMsg());
- SimMsg smR = send(smS, seat, sim, RETRY_COUNT_CLEAR_ONE_FAULT, commStrategy.getSleepLong());
- if (reF != null) {
- simReceiveService.clearOneFault(smR, sim, reF, f);
- } else {
- l.info("reF == null");
- }
- // step2
- // 下发故障独立运行。下面屏蔽。
- // if (reF != null &&
- // realExamFaultService.isState(reF.getRefId(), RealExamFault.State.CLEARED)) {
- // if (reF.getFlag().equals(RealExamFault.Flag.YES)) {
- // writeOneFault(s, reF, f);
- // } else if (reF.getFlag().equals(RealExamFault.Flag.NO)) {
- // RealExamFault f1 = realExamFaultService.selectRealExamFaultByRefId(reF.getRefId());
- // f1.setRefState(RealExamFault.State.LOOP_READ);
- // }
- // }
- }
- /**
- * debug下发一个故障
- *
- * @param seatId
- * @param bindHardwareMsg
- * @return
- * @throws IOException
- */
- public SimMsg debugWriteOneFault(final Long seatId, final String bindHardwareMsg) {
- Seat seat = seatService.selectSeatBySeatId(seatId);
- Sim sim = getSimBySeatIdNewVer(seatId);
- SimMsg sm = commBuildService.buildSendMsgWriteFault(sim.getSimNum(), bindHardwareMsg);
- return send(sm, seat, sim, RETRY_COUNT_WRITE_ONE_FAULT, commStrategy.getSleepLong());
- }
- /**
- * debug下发所有故障
- *
- * @param seatId
- * @return
- * @throws IOException
- */
- public List<SimMsg> debugWriteAllFault(final Long seatId) {
- List<SimMsg> list = new ArrayList<>();
- Sim sim = getSimBySeatIdNewVer(seatId);
- String simType = sim.getSimType();
- for (String bind : getGZBWBySimType(simType)) {
- list.add(debugWriteOneFault(seatId, bind));
- }
- return list;
- }
- /**
- * todo:尚未实现
- * 实现方式类似 studentStartRealExam方法。
- *
- * @param seatId
- * @param faultIds
- * @param checkReplace 是否进行可换件检查
- * @return
- */
- @Transactional
- public AjaxResult debugWriteSelectedFaultBySeatId(final Long seatId, final String[] faultIds, final Boolean checkReplace) {
- // Check:seatId有效性
- {
- AjaxResult ar = debugCheckSeatId(seatId);
- if (ar.isError()) {
- return ar;
- }
- }
- // Check:faultIds有效性
- {
- if (faultIds == null || faultIds.length == 0) {
- return AjaxResult.error("下发故障数据为空!");
- }
- }
- // 删除调试表故障数据。
- debugFaultService.deleteAll();
- //
- Seat seat = seatService.selectSeatBySeatId(seatId);
- Sim sim = getSimBySeatIdNewVer(seatId);
- // check sim
- // 打开socket
- {
- socketService.tryOpenAll();
- }
- // Step 1 主动查询一次模拟器状态。
- {
- AjaxResult arE3 = checkOneSimStateActive(seat);
- if (arE3.isError()) {
- return arE3;
- }
- }
- sim = simService.uniqueBySimNum(sim.getSimNum());
- // Step 2
- // msg判断,是否含有"故障部位"字符串
- {
- if (checkReplace) {
- AjaxResult arE2 = readOneSimAllFaultStartCheck(seat, sim);
- if (arE2.isError()) {
- return arE2;
- }
- }
- }
- // Step 3 清除对应一台模拟器 所有故障部位故障。
- {
- clearOneSimAllFaultBySim(seat, sim);
- }
- // Step 4 下发对应一台模拟器 出题选中的 故障位置故障。
- {
- Fault[] faults = new Fault[faultIds.length];
- for (int i = 0; i < faultIds.length; i++) {
- faults[i] = faultService.selectFaultByFaultId(faultIds[i]);
- }
- writeOneSimAllSelectFaultByDebug(seat, sim, faults);
- }
- // Step 5 读取
- {
- readOneSimAllFaultFirstTimeBySim(seat, sim, faultIds);
- }
- return AjaxResult.success("下发故障流程执行成功!" + SimDateUtil.getNow());
- }
- /**
- * debug校验seatId
- *
- * @param seatId
- * @return
- */
- public AjaxResult debugCheckSeatId(final Long seatId) {
- if (seatId == null || seatId <= 0) {
- return AjaxResult.error("座次信息不正确!");
- }
- Seat seat = seatService.selectSeatBySeatId(seatId);
- if (seat == null) {
- return AjaxResult.error("座次信息不存在!");
- }
- return AjaxResult.success();
- }
- /**
- * debug扫描所有座次模拟器
- *
- * @return
- */
- public AjaxResult debugScanAllSeat() {
- List<ScanSeatVo> list = new ArrayList<>();
- seatService.listAllEnable().forEach(seat -> {
- AjaxResult ar = commCheckService.checkOneSeatState(seat, true);
- String text = ar.get(AjaxResult.MSG_TAG).toString();
- // 新查询
- seat = seatService.selectSeatBySeatId(seat.getSeatId());
- // 座上sim
- Sim sim = simService.selectSimBySimId(seat.getCurrentSimId());
- if (sim != null) {
- list.add(new ScanSeatVo(seat.getSeatId(), sim.getSimId(), sim.getSimType(), text));
- } else {
- list.add(new ScanSeatVo(seat.getSeatId(), 0L, "", text));
- }
- });
- return AjaxResult.success(list);
- }
- private String[] getGZBWBySimType(String simType) {
- if (StringUtils.isBlank(simType)) {
- return new String[0];
- }
- switch (simType) {
- case Sim.TYPE_0001 -> {
- return TYPE_1_BIND_MSG;
- }
- case Sim.TYPE_0002 -> {
- return TYPE_2_BIND_MSG;
- }
- case Sim.TYPE_0003 -> {
- return TYPE_3_BIND_MSG;
- }
- default -> {
- return new String[0];
- }
- }
- }
- /**
- * 下发所有选中的真实的故障部位。
- *
- * @param re
- */
- public void writeOneSimAllSelectFaultByExam(RealExam re) {
- // 更新Exam状态。
- realExamService.updateOneState(re.getExamId(), RealExam.State.SIM_WRITING);
- List<RealExamFault> list = realExamFaultService.listAllType2FlagYesClearedStateByExamId(re.getExamId());
- for (RealExamFault ref : list) {
- Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
- Sim sim = simService.selectSimBySimId(re.getSimId());
- Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
- // 选中的故障才下发。
- writeOneSimOneFault(seat, sim, ref, f);
- }
- }
- public void writeOneSimAllSelectFaultByDebug(Seat seat, Sim sim, Fault[] faults) {
- for (Fault f : faults) {
- writeOneSimOneFault(seat, sim, null, f);
- }
- }
- public void writeOneSimOneFault(Seat seat, Sim sim, RealExamFault ref, Fault f) {
- l.info("下发故障:getSimId = {},fault.getName = {}", sim.getSimId(), f.getName());
- // todo:ref is null.
- // 下发故障
- SimMsg smA1 = commBuildService.buildSendMsgWriteFault(sim.getSimNum(), f.getBindHardwareMsg());
- SimMsg smA2 = send(smA1, seat, sim, RETRY_COUNT_WRITE_ONE_FAULT, commStrategy.getSleepLong());
- }
- /**
- * 一个模拟器 所有故障 开始考试前 检查读取。
- * 有两处引用。正式开始和调试。
- *
- * @param seat
- * @param sim
- * @return
- */
- public AjaxResult readOneSimAllFaultStartCheck(final Seat seat, final Sim sim) {
- // 查询某型号所有真实的故障部位。
- Fault q = new Fault();
- q.setFaultType(Fault.Type.REAL_GZBW);
- q.setSimType(sim.getSimType());
- List<Fault> listF = faultService.selectFaultList(q);
- // 未正确安装可换件故障List
- // NG not good
- List<FaultCheckVo> listNGVo = new ArrayList<>();
- // not good fault_id HashSet
- Set<String> setNG = new HashSet<>();
- // 单一故障部位检查
- {
- for (Fault oneF : listF) {
- FaultCheckVo voOne = new FaultCheckVo();
- voOne.setSeat(seat);
- voOne.setSim(sim);
- voOne.setFault(oneF);
- AjaxResult ar = readOneSimOneFaultStartSimpleCheck(voOne);
- // getDefaultErrorAR voReturn 可能为空
- FaultCheckVo voReturn = (FaultCheckVo) ar.get(AjaxResult.DATA_TAG);
- if (voReturn != null) {
- if (voReturn.isCheckOk()) {
- l.info("log 故障部位[{}][{}]安装ok;", oneF.getBindHardwareMsg(), oneF.getReplaceName());
- } else {
- l.info("log 故障部位[{}][{}]未正确安装;", oneF.getBindHardwareMsg(), oneF.getReplaceName());
- listNGVo.add(voReturn);
- setNG.add(oneF.getFaultId());
- }
- }
- // 得出ar有问题直接返回,不执行后面检查。
- if (ar.isError()) {
- return ar;
- }
- }
- }
- // 复核条件检查
- {
- AjaxResult ar = readOneSimAllFaultStartGlobalCheck(sim, setNG);
- if (ar.isError()) {
- return ar;
- }
- }
- //
- if (!listNGVo.isEmpty()) {
- StringBuilder sb = new StringBuilder();
- for (FaultCheckVo oneVo : listNGVo) {
- sb.append(oneVo.getErrorMsg());
- }
- sb.append("请正确安装可换件,检查后重新开始!");
- return AjaxResult.error(sb.toString());
- }
- return AjaxResult.success("所有故障部位检查没有问题。");
- }
- private String buildKeyType0003(String bindHardwareMsg) {
- return buildKey(Sim.TYPE_0003, bindHardwareMsg);
- }
- private String buildKey(String simType, String bindHardwareMsg) {
- if (StringUtils.isAnyBlank(simType, bindHardwareMsg)) {
- throw new IllegalArgumentException("isAnyBlank");
- }
- return simType + "@" + bindHardwareMsg;
- }
- /**
- * 一个模拟器 全部故障 开始考试前 复合读取检查。
- *
- * @param sim
- * @param setNG
- * @return
- */
- public AjaxResult readOneSimAllFaultStartGlobalCheck(Sim sim, Set<String> setNG) {
- if (Objects.isNull(setNG) || setNG.isEmpty()) {
- return AjaxResult.success("");
- }
- if (StringUtils.equals(sim.getSimType(), Sim.TYPE_0003)) {
- // if (map.containsKey(buildKeyType0003("01"))) {
- // SimMsg smR = map.get(buildKeyType0003("01")).getSimMsgReceive();
- // String smRS = CommParseUtils.subContentData(smR);
- // // 没有连接FFC排线
- // if (StringUtils.endsWith(smRS, "02")) {
- // return AjaxResult.error("请检查FFC排线连接!");
- // } else if (StringUtils.endsWith(smRS, "01")) {
- //
- // }
- // }
- if (setNG.contains(FaultIdConst.T0003.F03) &&
- setNG.contains(FaultIdConst.T0003.F04) &&
- setNG.contains(FaultIdConst.T0003.F0B) &&
- setNG.contains(FaultIdConst.T0003.F0E)
- ) {
- return AjaxResult.error("请检查 显控报警板与主板连接线 连接情况!");
- }
- }
- return AjaxResult.success("复合读取检查 成功。");
- }
- /**
- * 一个模拟器 一个故障 开始考试前 简单读取检查。
- *
- * @param vo
- * @return
- */
- public AjaxResult readOneSimOneFaultStartSimpleCheck(FaultCheckVo vo) {
- l.info("readOneSimOneFaultCheck vo = {}", vo);
- SimMsg smS = commBuildService.buildSendMsgReadFaultResistance(vo.getSim().getSimNum(), vo.getFault().getBindHardwareMsg());
- SimMsg smR = send(smS, vo.getSeat(), vo.getSim(), RETRY_COUNT_CHECK_ONE_FAULT, commStrategy.getSleepLong());
- if (smR.isResultNotOk()) {
- if (Objects.equals(smR.getResult(), SimMsg.Result.RECEIVE_CHECK_FAIL) ||
- (Objects.equals(smR.getResult(), SimMsg.Result.RECEIVE_NOT_MATCH))) {
- l.info("reset connection!");
- String ip = vo.getSeat().getSeatRs485Ip();
- Integer port = vo.getSeat().getSeatRs485Port();
- SimSocketParamVo sspv = new SimSocketParamVo(ip, port);
- socketService.closeOne(sspv, true);
- }
- return smR.getDefaultErrorAR();
- }
- // set send and receive msg.
- vo.setSimMsgSend(smS);
- vo.setSimMsgReceive(smR);
- return simReceiveService.getOneFaultCheck(vo);
- }
- /**
- * 第一次读取,作为出题值。
- *
- * @param re
- */
- public void readOneSimAllFaultFirstTimeByExam(RealExam re) {
- l.info("readOneSimAllFaultFirstTimeByExam re = {}", re);
- List<RealExamFault> list = realExamFaultService.listAllType2(re.getExamId());
- for (RealExamFault ref : list) {
- Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
- Sim sim = simService.selectSimBySimId(re.getSimId());
- Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
- readOneSimOneFaultFirstTime(seat, sim, ref, f, null);
- }
- }
- /**
- * 第一次读取,作为出题值。debug模式。
- *
- * @param seat
- * @param sim
- * @param faultIds debug模式必须有值
- */
- public void readOneSimAllFaultFirstTimeBySim(Seat seat, Sim sim, final String[] faultIds) {
- l.info("readOneSimAllFaultFirstTimeBySim s = {}", sim);
- List<Fault> list = faultService.listType3(sim.getSimType());
- for (Fault f : list) {
- readOneSimOneFaultFirstTime(seat, sim, null, f, faultIds);
- }
- }
- /**
- * 第一次读取,作为出题值。
- *
- * @param sim
- * @param ref debug调试模式为空。可以为空。
- * @param fault
- * @param faultIds debug模式必须有值
- */
- public void readOneSimOneFaultFirstTime(Seat seat, Sim sim, RealExamFault ref, Fault fault, String[] faultIds) {
- l.info("readOneSimOneFaultFirstTime");
- // 读取一次当前电阻代表值作为出题值。
- SimMsg smS = commBuildService.buildSendMsgReadFaultResistance(sim.getSimNum(), fault.getBindHardwareMsg());
- SimMsg smR = send(smS, seat, sim, RETRY_COUNT_WRITE_ONE_FAULT, commStrategy.getSleepLong());
- simReceiveService.setFaultQuestionValue(smR, sim, ref, fault, faultIds);
- }
- /**
- * debug读取一个故障位置数据
- *
- * @param seatId
- * @param bindHardwareMsg
- * @return
- */
- public SimMsg debugReadOneFaultResistance(final Long seatId, final String bindHardwareMsg) {
- Seat seat = seatService.selectSeatBySeatId(seatId);
- Sim sim = getSimBySeatIdNewVer(seatId);
- SimMsg sm = commBuildService.buildSendMsgReadFaultResistance(sim.getSimNum(), bindHardwareMsg);
- return send(sm, seat, null, RETRY_COUNT_0, commStrategy.getSleepShort());
- }
- /**
- * debug读取全部故障位置数据
- *
- * @param seatId
- * @return
- */
- public List<SimMsg> debugReadAllFaultResistance(final Long seatId) {
- Sim sim = getSimBySeatIdNewVer(seatId);
- List<SimMsg> list = new ArrayList<>();
- String simType = simService.uniqueBySimNum(sim.getSimNum()).getSimType();
- for (String b : getGZBWBySimType(simType)) {
- list.add(debugReadOneFaultResistance(seatId, b));
- }
- return list;
- }
- /**
- * 读取一个模拟器的一个故障点位的值。
- *
- * @param sim
- * @param reF
- * @param fault
- * @param refState 修改的目标状态。debug模式下执行为null。
- */
- public void readOneSimOneFaultResistance(Seat seat, Sim sim, RealExamFault reF, Fault fault, final String refState) {
- l.info("readOneSimOneFaultResistance");
- SimMsg smS = commBuildService.buildSendMsgReadFaultResistance(sim.getSimNum(), fault.getBindHardwareMsg());
- SimMsg sm2 = null;
- if (reF != null && refState != null) {
- if (StringUtils.equals(refState, RealExamFault.State.LOOP_READ)) { // 是否是中间读取
- sm2 = send(smS, seat, sim, RETRY_COUNT_READ_ONE_RESISTANCE_MIDDLE, commStrategy.getSleepShort(), false);
- } else if (StringUtils.equals(refState, RealExamFault.State.FINISH)) { // 是否最后一次读取。
- sm2 = send(smS, seat, sim, RETRY_COUNT_READ_ONE_RESISTANCE_FINAL, commStrategy.getSleepShort());
- } else {
- sm2 = send(smS, seat, sim, RETRY_COUNT_0, commStrategy.getSleepShort());
- }
- } else {
- sm2 = send(smS, seat, sim, RETRY_COUNT_READ_ONE_RESISTANCE_FINAL, commStrategy.getSleepShort());
- }
- simReceiveService.setFaultAnswerValue(sm2, sim, reF, fault, refState);
- }
- public SimMsg send(final SimMsg sm, final Seat seat, final Sim sim, final int retryTotalCount, final long sleep) {
- return send(sm, seat, sim, retryTotalCount, sleep, true);
- }
- /**
- * 最基本的通信方法。
- * send hex message
- * <p>
- * 去掉synchronized
- *
- * @param sm 发送
- * @param seat 不能为空
- * @param sim 可以为空!更新最后发送/接收时间 用。
- * @param retryTotalCount 重试次数
- * @param sleep 不使用传入0,不进行挂起。
- * @param importantTask 是否是重要的。
- * @return
- */
- public SimMsg send(final SimMsg sm, final Seat seat, final Sim sim, final int retryTotalCount, final long sleep, final boolean importantTask) {
- if (!config.isCommGlobal()) {
- l.warn("isCommGlobal == false [模拟器通信被禁用!]");
- return sm;
- }
- if (sm == null || sm.getSendMsg() == null || StringUtils.isBlank(sm.getSendMsg())) {
- throw new IllegalArgumentException("SimMsg IllegalArgument");
- }
- // sim
- if (seat == null) {
- throw new IllegalArgumentException("seat is null");
- }
- if (sleep < 0) {
- throw new IllegalArgumentException("SimMsg sleep");
- }
- // log.
- {
- l.info("####发送#### == Seat[{}],SimMsg[{}]", seat, sm);
- }
- SimSocketParamVo sspv = seat.toSimSocketParamVo();
- try {
- // 如果没有打开socket,顺道打开。正好后面要sleep。
- // 不强制重开Socket。
- // 先进行Socket相关处理。
- // 优先级高的在运行,跳过
- if (importantTask == false && socketService.getImportantTaskRunning(sspv)) {
- sm.setResult(SimMsg.Result.SKIP);
- socketService.setImportantTaskRunning(sspv, false);
- l.warn("####跳过运行#### sm = {}", sm);
- return sm;
- }
- if (importantTask) {
- socketService.setImportantTaskRunning(sspv, true);
- }
- socketService.openOne(sspv);
- // Socket情况不正确,直接返回。
- if (socketService.isNotOk(sspv)) {
- sm.setResult(SimMsg.Result.SOCKET_CONNECT_EXCEPTION);
- socketService.setImportantTaskRunning(sspv, false);
- return sm;
- }
- {
- // sleep挂起线程,追求顺序请求。
- // 大于0才挂起。
- if (sleep > 0 && socketService.getVo(sspv).getPreviousSendSleep() > 0L) {
- // 时间间隔挂起。
- Thread.sleep(socketService.getVo(sspv).getPreviousSendSleep());
- }
- }
- socketService.getVo(sspv).setPreviousSendSleep(sleep);
- Socket socket = socketService.getVo(sspv).getSocket();
- InputStream is = socket.getInputStream();
- OutputStream os = socket.getOutputStream();
- Sim simSeat = simService.selectSimBySimId(seat.getCurrentSimId());
- socket.setSoTimeout(commStrategy.getSoTimeout(simSeat));
- os.write(hexStrToByteArrs(sm.getSendMsg()));
- sm.setSendTime(DateUtils.getNowDate());
- if (sim != null) {
- simService.updateLastSentTime(sim);
- }
- byte[] buffer = new byte[LENGTH_24];
- int length = is.read(buffer);
- StringBuilder sbHex = new StringBuilder();
- for (int i = 0; i < length; i++) {
- sbHex.append(String.format("%02X", buffer[i]));
- }
- String receiveWith0 = sbHex.toString();
- // 原始带0的收到报文。
- sm.setReceiveOriginalMsg(receiveWith0);
- sm.setReceiveMsg(commReceiveService.removeRrdfix0(receiveWith0));
- sm.setReceiveTime(DateUtils.getNowDate());
- // log.
- {
- AjaxResult ar = commReceiveService.checkReceiveMsgFormat(sm.getReceiveMsg());
- if (ar.isError()) {
- // todo:
- l.warn("####接收错误@格式错误#### = sm = {},ar = {}", sm, ar);
- sm.setResult(SimMsg.Result.RECEIVE_CHECK_FAIL);
- socketService.setImportantTaskRunning(sspv, false);
- return sm;
- }
- }
- {
- AjaxResult ar = commReceiveService.checkReceiveMsgMatch(sm);
- if (ar.isError()) {
- l.warn("####接收错误@匹配错误#### sm = {},ar = {}", sm, ar);
- sm.setResult(SimMsg.Result.RECEIVE_NOT_MATCH);
- socketService.setImportantTaskRunning(sspv, false);
- return sm;
- }
- }
- l.info("####接收成功#### = {}", sm);
- if (sim != null) {
- simService.updateLastReceivedTime(sim);
- }
- sm.setResult(SimMsg.Result.SUCCESS);
- socketService.setImportantTaskRunning(sspv, false);
- // 最后返回报文实体。
- return sm;
- } catch (InterruptedException | IOException e) {
- // SocketTimeoutException
- l.error("SocketTimeoutException");
- e.printStackTrace();
- sm.setResult(SimMsg.Result.READ_TIMEOUT_EXCEPTION);
- socketService.setImportantTaskRunning(sspv, false);
- if (sim != null) {
- l.info("fail sim.getSimId() = {}", sim.getSimId());
- }
- // Socket失败计数
- socketService.failedPlus1(sspv);
- if (socketService.failedIsReachedMax(sspv, SocketService.SOCKET_CONNECT_RETRY_COUNT_LIMIT)) {
- // 达到重试次数上限,认为模拟器离线
- if (sim != null) {
- simService.updateSimStateBySimId(sim.getSimId(), Sim.State.OFFLINE);
- }
- socketService.failedReset0(sspv);
- }
- // 先考虑一台模拟器演示。
- // 进行重试 start
- if (sm.getRetryCount() == RETRY_COUNT_0) {
- l.warn("####RetryTotalCount不重试RETRY_COUNT_0#### = getSimMsgId = {}", sm.getSimMsgId());
- return sm;
- }
- if (sm.getRetryCount() < retryTotalCount) {
- sm.retryCountPlus1();
- send(sm, seat, sim, retryTotalCount, sleep);
- l.warn("####RetryTotalCount重试#### = {}", sm);
- } else {
- l.warn("####RetryTotalCount达到重试上限#### = {}", sm);
- }
- // 进行重试 end
- // 最后返回报文实体。
- return sm;
- }
- }
- /**
- * todo:
- *
- * @param sm
- * @param s
- * @param retryTotalCount
- * @param sleep
- * @return
- */
- public SimMsg sendRetry(final SimMsg sm, final Sim s, final int retryTotalCount, final long sleep) {
- return null;
- }
- /**
- * https://mvnrepository.com/artifact/com.infiniteautomation/modbus4j/3.0.3
- */
- public void test02() {
- byte[] data = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02}; // 示例数据
- // int crc = ModbusUtils.calculateCRC(data);
- // System.out.println("CRC-16/MODBUS 校验值: " + Integer.toHexString(crc));
- }
- public static byte[] hexStrToByteArrs(String hexString) {
- // if (StringUtils.isEmpty(hexString)) {
- // return null;
- // }
- hexString = hexString.replaceAll(" ", "");
- int len = hexString.length();
- int index = 0;
- byte[] bytes = new byte[len / 2];
- while (index < len) {
- String sub = hexString.substring(index, index + 2);
- bytes[index / 2] = (byte) Integer.parseInt(sub, 16);
- index += 2;
- }
- return bytes;
- }
- public String logBytesToString(byte[] bytes) {
- if (bytes == null || bytes.length == 0) {
- return "";
- }
- StringBuffer sbHex = new StringBuffer();
- byte[] buffer = new byte[bytes.length];
- for (int i = 0; i < bytes.length; i++) {
- sbHex.append(String.format("%02X", buffer[i]));
- }
- return sbHex.toString();
- }
- public static String bytesToHexV2(byte[] bytes) {
- StringBuilder hexString = new StringBuilder();
- for (byte b : bytes) {
- String hex = Integer.toHexString(0xFF & b); // 将字节转换为十六进制字符串
- if (hex.length() == 1) {
- hexString.append('0'); // 如果是单个字符,补零
- }
- hexString.append(hex);
- }
- return hexString.toString();
- }
- /**
- * checkOneSeatState 包装调用。
- * seatId映射到Sim对象。
- *
- * @param seatId
- * @return 可能为空
- */
- public Sim getSimBySeatIdNewVer(Long seatId) {
- Seat seat = seatService.selectSeatBySeatId(seatId);
- // 执行在线监测。
- AjaxResult ar = commCheckService.checkOneSeatState(seat, true);
- if (ar != null) {
- return (Sim) ar.get(AjaxResult.DATA_TAG);
- } else {
- return null;
- }
- }
- /**
- * todo:
- *
- * @return
- */
- public AjaxResult debugResetAnything() {
- // Step:关闭所有Socket连接
- socketService.closeAll();
- // Step:ping路由器,返回在线情况。
- // Step:ping教员端主机,返回在线情况。
- // Step:ping所有学员端主机,返回在线情况列表。
- // Step:ping所有RS485,返回在线情况列表。
- // Step:建立所有模拟器Socket,返回情况列表。
- // Step:有Socket的前提下,尝试查询所有模拟器连接情况,得到连接的模拟器 型号、序列号信息
- // Step:所有连接的模拟器,清除每一个模拟器的各个故障
- // Step:所有连接的模拟器,读取每一个模拟器的各个故障,是否处于考试准备ok状态
- // 删除debug表中所有数据。
- debugFaultService.deleteAll();
- return AjaxResult.success("全部重置成功。" + SimDateUtil.getNow());
- }
- /**
- * 每30s执行一次。
- */
- public void scheduledChargingCount() {
- // 查询到唯一打开的 考试 或 训练
- RealExamCollection rec = realExamCollectionService.selectRealExamCollectionOpenedNotSelfExercise();
- //
- if (rec == null) {
- l.info("rec == null!");
- return;
- }
- Long recId = rec.getExamCollectionId();
- RealExam q = new RealExam();
- q.setExamCollectionId(recId);
- // 只需要0002型模拟器。
- q.setSimType(Sim.TYPE_0002);
- List<RealExam> list = realExamService.selectRealExamList(q);
- if (list == null || list.isEmpty()) {
- return;
- }
- list.forEach((RealExam re) -> {
- if (re == null || re.getExamId() == null || re.getExamId() == 0L) {
- return;
- }
- if (StringUtils.equals(re.getExamStatus(), RealExam.State.LOGGED_IN)) {
- Seat qSeat = seatService.selectSeatBySeatId(re.getSeatId());
- // 检查后就知道seat上是否有sim
- AjaxResult ar = commCheckService.checkOneSeatState(qSeat, true);
- if (ar.isSuccess()) {
- // 获取当前simId
- Long currSimId = seatService.selectSeatBySeatId(re.getSeatId()).getCurrentSimId();
- if (!currSimId.equals(Sim.ID_0)) {
- Integer count = simService.updateChargingCountPlusBySimId(currSimId);
- l.info("scheduledChargingCount count = {}", count);
- } else {
- l.info("scheduledChargingCount Sim.ID_0 seatId = {}", qSeat.getSeatId());
- }
- } else {
- l.info("checkOneSeatState failed");
- }
- } else {
- l.info("skip");
- }
- });
- }
- }
|