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.config.SimDebugConfig; import com.ruoyi.sim.domain.*; 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 java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; 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); /** * 缓存的Socket连接。 */ private Socket cachedSocket = null; @Autowired private CommReceiveService simReceiveService; @Autowired private SimService simService; @Autowired private FaultService faultService; @Autowired private RealExamService realExamService; @Autowired private RealExamFaultService realExamFaultService; @Autowired private RealExamCollectionService realExamCollectionService; @Autowired private SimConfig config; @Autowired private CommBuildService commBuildService; @Autowired private DebugFaultService debugFaultService; /** * 定时任务。 */ public void scheduledLoopRead() { readAll(); } public void readAll() { l.info("readAll"); List listRe = realExamService.listAllByStatus(RealExam.State.ANSWERING); listRe.forEach(e -> { if (e == null) { return; } List listRef = realExamFaultService.listAllType2State2and3ByExamId(e.getExamId()); listRef.forEach(ref -> { Sim s = simService.selectSimBySimId(e.getSimId()); Fault f = faultService.selectFaultByFaultId(ref.getFaultId()); if (f != null && Fault.Type.REAL_GZBW.equals(f.getFaultType()) && Fault.State.ENABLE.equals(f.getFaultState()) ) { readOneSimOneFaultResistance(s, ref, f, null); } }); }); } /** * Async version. */ @Async("tp-comm") public void readAllAsync() { readAll(); } public void readOneExamAtLast(RealExam re) { l.info("readOneExamAtLast"); List list = realExamFaultService.listAllType2State2and3ByExamId(re.getExamId()); for (RealExamFault ref : list) { Sim s = simService.selectSimBySimId(re.getSimId()); Fault f = faultService.selectFaultByFaultId(ref.getFaultId()); readOneSimOneFaultResistance(s, ref, f, RealExamFault.State.FINISH); } // 计算扣分。 // 最后都读取到,才算扣分。 { // todo:暂时不算。 // calculateScore(re.getExamId()); } } public void readOneSimAtLastByDebug(Sim s) { l.info("readOneSimAtLastByDebug"); List list = faultService.listType3(s.getSimType()); for (Fault f : list) { readOneSimOneFaultResistance(s, null, f, null); } } public AjaxResult debugReadAllFaultResistanceBySimNum(String simNum) { // check // // 打开socket { AjaxResult ar1 = openSocket(); if (ar1.isError()) { return ar1; } } // Sim s = simService.uniqueBySimNum(simNum); { AjaxResult arE3 = checkOneSimStateActive(s); if (arE3.isError()) { return arE3; } } s = simService.uniqueBySimNum(simNum); // todo: aj改造 readOneSimAtLastByDebug(s); 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.existOpened()) { 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); l.info("cachedSocket.isConnected():" + cachedSocket.isConnected()); l.info("cachedSocket.isBound():" + cachedSocket.isBound()); l.info("cachedSocket.isClosed():" + cachedSocket.isClosed()); l.info("cachedSocket.isInputShutdown():" + cachedSocket.isInputShutdown()); l.info("cachedSocket.isOutputShutdown():" + cachedSocket.isOutputShutdown()); // debugReadAllFaultResistance(simNum, simType); // debugWriteAllFault(simNum, simType); // for (int i = 0; i < 5; i++) { // debugReadAllFaultResistance(simNum, simType); // } // if (isSocketOk()) { // readAllAsync(); // } else { // scheduledConnect(); // } } /** * 连接情况 的 定时任务。 * 执行频率: 2min debug:30s */ public void scheduledConnect() { l.info("scheduled####Connect 连接情况 的 定时任务"); if (!SimDebugConfig.SCHEDULED_CONNECT) { l.info("连接情况 的 定时任务被禁用!"); return; } if (!realExamCollectionService.existOpened()) { l.info("没有open的考试集合"); return; } if (!isReachable(config.getRouterIp())) { l.warn("ping RouterIp not ok"); simService.updateAllEnableState(Sim.State.GATEWAY_OFFLINE); return; } if (!isReachable(config.getRs485Ip())) { l.warn("ping Rs485Ip not ok"); simService.updateAllEnableState(Sim.State.GATEWAY_OFFLINE); return; } openSocket(); if (isCachedSocketOk()) { checkAllSimState(); } } /** * 主动更新模拟器状态。 * * @param s * @return */ public AjaxResult checkOneSimStateActive(Sim s) { long simId = s.getSimId(); // 这句可能会调整模拟器状态 checkOneSimState(s, true); // s = simService.selectSimBySimId(simId); // 如果模拟器离线 if (s != null && Sim.State.ONLINE.equals(s.getSimState())) { return AjaxResult.success(); } else { return AjaxResult.error("未连接模拟器,请检查连接!"); } } /** * @param s */ public void checkOneSimState(final Sim s, final boolean important) { // check if (s == null) { return; } if (Sim.State.DISABLE.equals(s.getSimState())) { l.warn("sim DISABLE,模拟器被禁用,sim = {}", s); return; } if (StringUtils.isBlank(s.getSimType()) || StringUtils.isBlank(s.getSimNum())) { l.warn("sim error data {}", s); return; } // SimMsg smS = commBuildService.buildSendMsgReadSimType(s.getSimNum()); int retryCount = RETRY_COUNT_0; long sleep = SLEEP_SHORT; if (important) { retryCount = RETRY_COUNT_QUERY_SN_IMPORTANT; } SimMsg smR = send(smS, s, retryCount, sleep); if (StringUtils.isNotBlank(smR.getReceiveMsg())) { l.info("isNotBlank"); commFailCountClearOne(s.getSimId()); } simReceiveService.checkOneSimState(smR, s); } /** * 查找所有没有被手动禁用,并order by sim_num的模拟器列表。检查所有模拟器状态。 */ public void checkAllSimState() { RealExamCollection ecF = realExamCollectionService.selectRealExamCollectionOpened(); l.info("ecF.getSimType() = {}", ecF.getSimType()); if (ecF != null) { List list = simService.listAllEnableBySimType(ecF.getSimType()); l.info("checkAllSimState list.size() = {}", list.size()); list.forEach(s -> { checkOneSimState(s, false); }); } } @Async("tp-comm") public void checkAllSimStateAsync() { checkAllSimState(); } /** * 清除一个考试的,对应的某型号一台模拟器的,所有故障部位。 * * @param re */ public void clearOneSimAllFaultByExam(RealExam re) { l.info("clearOneSimAllFaultByExam = {}", re); // check // 更新Exam状态。 { realExamService.updateOneState(re.getExamId(), RealExam.State.SIM_WRITING); } // List list = realExamFaultService.listAllType2InitStateByExamId(re.getExamId()); if (list != null) { l.info("清除exam list = {}", list.size()); } assert list != null; list .forEach(ref -> { Fault f = faultService.selectFaultByFaultId(ref.getFaultId()); if (faultService.isDisable(f.getFaultId())) { l.warn("故障 {} -被禁用", f.getName()); throw new IllegalArgumentException("故障被禁用"); } Sim s = simService.selectSimBySimId(re.getSimId()); // check // clearOneSimOneFault(s, ref, f); }); } public void clearOneSimAllFaultBySim(Sim s) { l.info("clearOneSimAllFaultBySim = {}", s); faultService.listType3EnableBySimType(s.getSimType()) .forEach(f -> { clearOneSimOneFault(s, null, f); }); } /** * Async version. * * @param re */ @Async("tp-comm") public void clearListFaultByRealExamAsync(RealExam re) { clearOneSimAllFaultByExam(re); } public void clearAll() { // todo: simService.listAllEnable().forEach(s -> { String simType = s.getSimType(); List listF = faultService.listType3EnableBySimType(simType); listF.forEach(f -> { clearOneSimOneFault(s, null, f); }); }); } /** * debug读取模拟器类型序列号 * * @param simNum * @return */ public SimMsg debugReadSimType(final String simNum) { SimMsg sm = commBuildService.buildSendMsgReadSimType(simNum); return send(sm, null, RETRY_COUNT_0, SLEEP_SHORT); } /** * debug清除一个故障 * * @param simNum * @param bindHardwareMsg * @return */ public SimMsg debugClearOneFault(final String simNum, final String bindHardwareMsg) { SimMsg sm = commBuildService.buildSendMsgClearFault(simNum, bindHardwareMsg); Sim s = simService.uniqueBySimNum(simNum); return send(sm, s, RETRY_COUNT_CLEAR_ONE_FAULT, SLEEP_LONG); } public AjaxResult debugClearAllOnlineSimAllFault() { l.info("debugClearAllOnlineSimAllFault"); simService.listAllOnline().forEach(s -> { AjaxResult ar = debugClearAllFaultBySimNum(s.getSimNum()); }); return AjaxResult.success("清除成功,清除所有在线模拟器所有故障!"); } /** * debug清除所有故障 * * @param simNum * @return */ public AjaxResult debugClearAllFaultBySimNum(final String simNum) { Sim s1 = simService.uniqueBySimNum(simNum); { AjaxResult arE3 = checkOneSimStateActive(s1); if (arE3.isError()) { return arE3; } } s1 = simService.uniqueBySimNum(simNum); if (s1 == null) { return AjaxResult.error("清除失败,对应simNum模拟器不存在!"); } if (!Sim.State.ONLINE.equals(s1.getSimState())) { return AjaxResult.error("清除失败,模拟器尚未在线!"); } List list = new ArrayList<>(); for (String b : getGZBWBySimType(s1.getSimType())) { SimMsg sm = debugClearOneFault(simNum, b); list.add(sm); if (sm != null && !sm.getOk()) { } } return AjaxResult.success("清除成功,清除当前模拟器所有故障!"); } /** * @param s * @param reF 可以为空,表示不关联考试的,单独执行的。调试模式下为空。 * @param f */ public void clearOneSimOneFault(Sim s, RealExamFault reF, Fault f) { l.info("clearOneSimOneFault 清除One故障:getSimNum = {},getBindHardwareMsg = {},fault.getName = {}", s.getSimNum(), f.getBindHardwareMsg(), f.getName()); // check todo: // step1 SimMsg smS = commBuildService.buildSendMsgClearFault(s.getSimNum(), f.getBindHardwareMsg()); SimMsg smR = send(smS, s, RETRY_COUNT_CLEAR_ONE_FAULT, SLEEP_LONG); if (reF != null) { simReceiveService.clearOneFault(smR, s, 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 simNum * @param bindHardwareMsg * @return * @throws IOException */ public SimMsg debugWriteOneFault(final String simNum, final String bindHardwareMsg) { SimMsg sm = commBuildService.buildSendMsgWriteFault(simNum, bindHardwareMsg); return send(sm, null, RETRY_COUNT_WRITE_ONE_FAULT, SLEEP_LONG); } /** * debug下发所有故障 * * @param simNum * @return * @throws IOException */ public List debugWriteAllFault(final String simNum) { List list = new ArrayList<>(); Sim s = simService.uniqueBySimNum(simNum); String simType = s.getSimType(); for (String b : getGZBWBySimType(simType)) { list.add(debugWriteOneFault(simNum, b)); } return list; } /** * todo:尚未实现 * 实现方式类似 studentStartRealExam方法。 * * @param simNum * @param faultIds * @param checkReplace 是否进行可换件检查 * @return */ public AjaxResult debugWriteSelectedFaultBySimNum(final String simNum, final String[] faultIds, final Boolean checkReplace) { // l.info("faultIds.length = {}", faultIds.length); { int deleteCount = debugFaultService.deleteAll(); l.info("deleteCount = {}", deleteCount); } // check faultIds 有效性 // Sim s = simService.uniqueBySimNum(simNum); // check sim // 打开socket { AjaxResult ar1 = openSocket(); l.info("ar1 = {}", ar1); if (ar1.isError()) { return ar1; } } // Step 1 主动查询一次模拟器状态。 { AjaxResult arE3 = checkOneSimStateActive(s); if (arE3.isError()) { return arE3; } } s = simService.uniqueBySimNum(simNum); // Step 2 // msg判断,是否含有"故障部位"字符串 { if (checkReplace) { AjaxResult arE2 = readOneSimAllFaultCheck(s); if (arE2.isError()) { return arE2; } } } // Step 3 清除对应一台模拟器 所有故障部位故障。 { clearOneSimAllFaultBySim(s); } // Step 4 下发对应一台模拟器 出题选中的 故障位置故障。 { Fault[] faults = new Fault[faultIds.length]; for (int i = 0; i < faultIds.length; i++) { faults[i] = faultService.selectFaultByFaultId(faultIds[i]); } writeOneSimAllSelectFaultByDebug(s, faults); } // Step 5 读取 { readOneSimAllFaultFirstTimeBySim(s, faultIds); } return AjaxResult.success("下发故障流程执行成功!"); } 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 list = realExamFaultService.listAllType2FlagYesClearedStateByExamId(re.getExamId()); for (RealExamFault ref : list) { Sim s = simService.selectSimBySimId(re.getSimId()); Fault f = faultService.selectFaultByFaultId(ref.getFaultId()); // 选中的才下发。 writeOneSimOneFault(s, ref, f); } } public void writeOneSimAllSelectFaultByDebug(Sim s, Fault[] faults) { for (Fault f : faults) { writeOneSimOneFault(s, null, f); } } public void writeOneSimOneFault(Sim s, RealExamFault ref, Fault f) { l.info("下发故障:getSimId = {},fault.getName = {}", s.getSimId(), f.getName()); // todo:ref is null. // 下发故障 SimMsg smA1 = commBuildService.buildSendMsgWriteFault(s.getSimNum(), f.getBindHardwareMsg()); SimMsg smA2 = send(smA1, s, RETRY_COUNT_WRITE_ONE_FAULT, SLEEP_LONG); } /** * 开始考试前检查读取。 * * @param s * @return */ public AjaxResult readOneSimAllFaultCheck(Sim s) { Fault q = new Fault(); q.setFaultType(Fault.Type.REAL_GZBW); q.setSimType(s.getSimType()); List list = faultService.selectFaultList(q); List listNG = new ArrayList<>(); for (Fault f : list) { AjaxResult ar = readOneSimOneFaultCheck(s, f); if (ar.isError()) { listNG.add(f); l.info("故障部位[" + f.getBindHardwareMsg() + "][" + f.getReplaceName() + "]未正确安装;"); } else { l.info("故障部位[" + f.getBindHardwareMsg() + "][" + f.getReplaceName() + "]安装ok;"); } } if (listNG.isEmpty()) { return AjaxResult.success("所有故障部位检查没有问题。"); } StringBuilder sbNG = new StringBuilder(); for (Fault f : listNG) { sbNG.append("[" + f.getReplaceName() + "]零件异常;
"); } sbNG.append("请检查后重新开始考试!"); return AjaxResult.error(sbNG.toString()); } /** * 检查读取。 * * @param s * @param f * @return */ public AjaxResult readOneSimOneFaultCheck(Sim s, Fault f) { l.info("readOneSimOneFaultCheck s = {},f = {}", s, f); SimMsg sm1 = commBuildService.buildSendMsgReadFaultResistance(s.getSimNum(), f.getBindHardwareMsg()); SimMsg sm2 = send(sm1, s, RETRY_COUNT_CHECK_ONE_FAULT, SLEEP_LONG); return simReceiveService.getOneFaultCheck(sm2, s, f); } /** * 第一次读取,作为出题值。 * * @param re */ public void readOneSimAllFaultFirstTimeByExam(RealExam re) { l.info("readOneSimAllFaultFirstTimeByExam re = {}", re); List list = realExamFaultService.listAllType2(re.getExamId()); for (RealExamFault ref : list) { Sim s = simService.selectSimBySimId(re.getSimId()); Fault f = faultService.selectFaultByFaultId(ref.getFaultId()); readOneSimOneFaultFirstTime(s, ref, f, null); } } /** * 第一次读取,作为出题值。debug模式。 * * @param s * @param faultIds */ public void readOneSimAllFaultFirstTimeBySim(Sim s, final String[] faultIds) { l.info("readOneSimAllFaultFirstTimeBySim s = {}", s); List list = faultService.listType3(s.getSimType()); for (Fault f : list) { readOneSimOneFaultFirstTime(s, null, f, faultIds); } } /** * 第一次读取,作为出题值。 * * @param s * @param ref debug调试模式为空。可以为空。 * @param f * @param faultIds debug调试模式为空。 */ public void readOneSimOneFaultFirstTime(Sim s, RealExamFault ref, Fault f, String[] faultIds) { l.info("readOneSimOneFaultFirstTime"); // 读取一次当前电阻代表值作为出题值。 SimMsg sm1 = commBuildService.buildSendMsgReadFaultResistance(s.getSimNum(), f.getBindHardwareMsg()); SimMsg sm2 = send(sm1, s, RETRY_COUNT_WRITE_ONE_FAULT, SLEEP_LONG); simReceiveService.setFaultQuestionValue(sm2, s, ref, f, faultIds); } /** * debug读取一个故障位置数据 * * @param simNum * @param bindHardwareMsg * @return * @throws IOException */ public SimMsg debugReadOneFaultResistance(final String simNum, final String bindHardwareMsg) { SimMsg sm = commBuildService.buildSendMsgReadFaultResistance(simNum, bindHardwareMsg); return send(sm, null, RETRY_COUNT_0, SLEEP_SHORT); } /** * debug读取全部故障位置数据 * * @param simNum * @return * @throws IOException */ public List debugReadAllFaultResistance(final String simNum) { List list = new ArrayList<>(); String simType = simService.uniqueBySimNum(simNum).getSimType(); for (String b : getGZBWBySimType(simType)) { list.add(debugReadOneFaultResistance(simNum, b)); } return list; } /** * @param s * @param reF * @param f * @param refState 中间轮询是null,交卷最后一次读取为finish状态。用来修改状态的。debug模式下执行为null。 */ public void readOneSimOneFaultResistance(Sim s, RealExamFault reF, Fault f, String refState) { l.info("readOneSimOneFaultResistance"); SimMsg sm1 = commBuildService.buildSendMsgReadFaultResistance(s.getSimNum(), f.getBindHardwareMsg()); SimMsg sm2 = null; if (reF != null && refState != null) { if (RealExamFault.State.FINISH.equals(refState)) { // 是否最后一次读取。 sm2 = send(sm1, s, RETRY_COUNT_READ_ONE_RESISTANCE, SLEEP_SHORT); } else { sm2 = send(sm1, s, RETRY_COUNT_0, SLEEP_SHORT); } } else { sm2 = send(sm1, s, RETRY_COUNT_READ_ONE_RESISTANCE, SLEEP_SHORT); } simReceiveService.setFaultAnswerValue(sm2, s, reF, f, refState); } private long previousSendSleep = 0; /** * send hex message * * @param sm 发送 * @param s 可以为空,更新最后发送/接收时间 用。 * @param retryTotalCount 重试次数 * @param sleep 不使用传入0,不进行挂起。 * @return */ public synchronized SimMsg send(final SimMsg sm, final Sim s, final int retryTotalCount, final long sleep) { try { if (!config.isCommGlobal()) { l.warn("isCommGlobal == false [模拟器通信被禁用!]"); return sm; } if (sm == null || sm.getSendMsg() == null || StringUtils.isBlank(sm.getSendMsg())) { throw new IllegalArgumentException("SimMsg IllegalArgument"); } if (sleep < 0) { throw new IllegalArgumentException("SimMsg sleep"); } // log. { l.info("####SendMsg#### == [{}]", sm); } // 如果没有打开socket,顺道打开。正好后面要sleep openSocket(); { // sleep ,追求顺序请求。 if (sleep > 0 && previousSendSleep != 0L) { Thread.sleep(previousSendSleep); } } previousSendSleep = sleep; InputStream is = cachedSocket.getInputStream(); OutputStream os = cachedSocket.getOutputStream(); os.write(hexStrToByteArrs(sm.getSendMsg())); sm.setSendTime(DateUtils.getNowDate()); if (s != null) { simService.updateLastSentTime(s); } byte[] buffer = new byte[LENGTH_24]; int length = is.read(buffer); StringBuffer sbHex = new StringBuffer(); for (int i = 0; i < length; i++) { sbHex.append(String.format("%02X", buffer[i])); } sm.setReceiveMsg(sbHex.toString()); sm.setReceiveTime(DateUtils.getNowDate()); // log. { l.info("####ReceiveMsg#### = [{}]", sm); } if (!commBuildService.checkReceiveMsg(sm.getReceiveMsg())) { // todo: l.warn("####Fail#### = {}", sm); return sm; } if (s != null) { simService.updateLastReceivedTime(s); } } catch (InterruptedException | IOException e) { // SocketTimeoutException e.printStackTrace(); // 失败计数 l.info("fail sim data = {}", s); boolean limit = commFailCountAdd1(Objects.requireNonNull(s).getSimId()); if (limit) { simService.updateSimStateBySimId(s.getSimId(), Sim.State.OFFLINE); commFailCountClearOne(s.getSimId()); } // 先考虑一台模拟器演示。 // 进行重试 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, s, 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; } /** * cachedSocket is ok * * @return */ public boolean isCachedSocketOk() { return (cachedSocket != null && cachedSocket.isConnected() && cachedSocket.isBound() && !cachedSocket.isClosed()); } /** * openSocket * * @return */ public AjaxResult openSocket() { // check if (!config.isCommGlobal()) { l.warn("isCommGlobal == false [模拟器通信被禁用!]"); return AjaxResult.error("模拟器通信被禁用!"); } try { if (!isCachedSocketOk()) { l.info("openSocket cachedSocket is not ok!new socket!"); cachedSocket = new Socket(config.getRs485Ip(), config.getRs485Port()); cachedSocket.setSoTimeout(SOCKET_TIME_OUT); commFailCountClearAll(); } else { l.info("openSocket cachedSocket is ok!"); } } catch (IOException e) { e.printStackTrace(); return AjaxResult.error("开启连接失败!请检查物联网网关连接或配置。"); } finally { } return AjaxResult.success("开启连接成功!"); } /** * closeSocket * * @return */ public AjaxResult closeSocket() { if (!config.isCommGlobal()) { l.warn("isCommGlobal == false [模拟器通信被禁用!]"); return AjaxResult.error("模拟器通信被禁用!"); } try { if (cachedSocket != null) { // todo:判断shutdown cachedSocket.getInputStream().close(); cachedSocket.getOutputStream().close(); cachedSocket.close(); } else { l.info("cachedSocket == null!"); } } catch (IOException e) { e.printStackTrace(); return AjaxResult.success("关闭连接失败!请检查物联网网关连接或配置。"); } finally { cachedSocket = null; commFailCountClearAll(); } return AjaxResult.success("关闭连接成功!"); } /** * 等同于ping命令。 * * @param ipV4 * @return * @throws IOException */ public boolean isReachable(String ipV4) { InetAddress ia = null; try { ia = InetAddress.getByName(ipV4); return ia.isReachable(2048); } catch (UnknownHostException e) { e.printStackTrace(); return false; } catch (IOException e) { e.printStackTrace(); return false; } } private HashMap map = new HashMap<>(); /** * @param simId * @return true超过通信失败次数限制 */ private boolean commFailCountAdd1(long simId) { l.info("map.containsKey(simId) = {}", map.containsKey(simId)); if (map.containsKey(simId)) { map.put(simId, map.get(simId) + 1); } else { map.put(simId, 1); } return (map.get(simId) >= OFFLINE_LIMIT); } private void commFailCountClearOne(long simId) { map.remove(simId); } private void commFailCountClearAll() { map.clear(); } /** * 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(); } }