CommSendService.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. package com.ruoyi.sim.service.impl;
  2. import com.ruoyi.sim.config.SimConfig;
  3. import com.ruoyi.sim.domain.*;
  4. import org.apache.commons.lang3.StringUtils;
  5. import org.slf4j.LoggerFactory;
  6. import org.slf4j.Logger;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.scheduling.annotation.Async;
  9. import org.springframework.stereotype.Service;
  10. import java.io.IOException;
  11. import java.io.InputStream;
  12. import java.io.OutputStream;
  13. import java.net.InetAddress;
  14. import java.net.Socket;
  15. import java.net.SocketTimeoutException;
  16. import java.util.List;
  17. import java.util.Objects;
  18. import static com.ruoyi.sim.service.impl.CommSendService.Const.*;
  19. /**
  20. * 硬件通信
  21. * send service.
  22. */
  23. @Service
  24. public class CommSendService {
  25. interface Const {
  26. String ROUTER_IP = "127.0.0.1";
  27. String IP = "123.112.16.165";
  28. int PORT = 8899;
  29. /**
  30. * 报文长度
  31. */
  32. int MSG_LENGTH = 20;
  33. String PREFIX = "AA";
  34. String SUFFIX = "55";
  35. /**
  36. * orientation
  37. */
  38. String ORN_SEND = "01";
  39. /**
  40. * orientation
  41. */
  42. String ORN_RECEIVE = "02";
  43. String CMD_DATA_PLACE_HOLDER = "00000000";
  44. /**
  45. * 故障下发
  46. */
  47. String CMD_SET_FAULT = "01";
  48. /**
  49. * 故障清清除
  50. */
  51. String CMD_CLEAR_FAULT = "02";
  52. /**
  53. * 设备类型读取
  54. */
  55. String CMD_READ_TYPE = "03";
  56. /**
  57. * 状态读取 RESISTANCE电阻值
  58. */
  59. String CMD_READ_FAULT_RESISTANCE = "03";
  60. String CMD_ID_GET_SN = "B1";
  61. int LENGTH_2 = 2;
  62. int LENGTH_8 = 8;
  63. int LENGTH_20 = 20;
  64. }
  65. private static final Logger l = LoggerFactory.getLogger(CommSendService.class);
  66. /**
  67. * 缓存的Socket连接。
  68. */
  69. private Socket cachedSocket = null;
  70. @Autowired
  71. private CommReceiveService simReceiveService;
  72. @Autowired
  73. private SimService simService;
  74. @Autowired
  75. private FaultService faultService;
  76. @Autowired
  77. private RealExamService realExamService;
  78. @Autowired
  79. private RealExamFaultService realExamFaultService;
  80. @Autowired
  81. private SimConfig sConfig;
  82. /**
  83. * 初始化方法,项目启动后自动运行。
  84. */
  85. public void init() {
  86. //
  87. try {
  88. if (!isReachable(ROUTER_IP)) {
  89. // todo:ping 不通。
  90. }
  91. if (!isReachable(IP)) {
  92. // todo:ping 不通。
  93. }
  94. openSocket();
  95. //
  96. checkAllSimState();
  97. } catch (IOException e) {
  98. throw new RuntimeException(e);
  99. }
  100. }
  101. /**
  102. * 定时任务。
  103. */
  104. public void scheduledLoopRead() {
  105. readAll();
  106. }
  107. public void readAll() {
  108. List<RealExam> listRE = realExamService.listAllStatus(RealExam.STATE_ANSWERING);
  109. listRE.forEach(e -> {
  110. if (e == null) {
  111. return;
  112. }
  113. List<RealExamFault> listREF = realExamFaultService.listAllType2YesLoopReadState(e.getExamId());
  114. listREF.forEach(ref -> {
  115. Sim s = simService.selectSimBySimId(e.getSimId());
  116. Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
  117. if (f != null &&
  118. f.getFaultType().equals(Fault.TYPE_3) &&
  119. f.getFaultState().equals(Fault.STATE_ENABLE)
  120. )
  121. readOneFaultResistance(s, ref, f);
  122. });
  123. });
  124. }
  125. /**
  126. * Async version.
  127. */
  128. @Async("tp-comm")
  129. public void readAllAsync() {
  130. readAll();
  131. }
  132. public void readOneExamAtLast(RealExam re) {
  133. List<RealExamFault> listREF = realExamFaultService.listAllType2YesLoopReadState(re.getExamId());
  134. listREF.forEach(ref -> {
  135. Sim s = simService.selectSimBySimId(re.getSimId());
  136. Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
  137. readOneFaultResistance(s, ref, f);
  138. });
  139. realExamService.updateOneState(re, RealExam.STATE_SUBMITTED);
  140. }
  141. /**
  142. * 定时任务。
  143. */
  144. public void scheduledCheckAllSimState() {
  145. checkAllSimState();
  146. }
  147. /**
  148. * 查找所有没有被手动禁用,并order by sim_num的模拟器列表。检查所有模拟器状态。
  149. */
  150. public void checkAllSimState() {
  151. List<Sim> list = simService.listAllEnable();
  152. list.forEach(s -> {
  153. checkOneSimState(s);
  154. });
  155. }
  156. @Async()
  157. public void checkAllSimStateAsync() {
  158. }
  159. public void checkOneSimState(Sim s) {
  160. l.info(s.toString());
  161. // check todo:
  162. if (Objects.isNull(s)) {
  163. return;
  164. }
  165. //
  166. try {
  167. SimMsg sm = new SimMsg();
  168. String sendMsg = buildSendMsgReadSimType(s.getSimNum());
  169. sm.setSendMsg(sendMsg);
  170. String receiveMsg = send(sendMsg, s);
  171. sm.setReceiveMsg(receiveMsg);
  172. simReceiveService.checkOneSimState(sm, s);
  173. } catch (IOException e) {
  174. throw new RuntimeException(e);
  175. }
  176. }
  177. /**
  178. * 清除一个考试的,对应的某型号一台模拟器的,所有设备故障。
  179. *
  180. * @param re
  181. */
  182. public void clearListFaultByRealExam(RealExam re) {
  183. // check
  184. if (Objects.isNull(re)) {
  185. }
  186. //
  187. List<RealExamFault> list = realExamFaultService.listAllType2InitStateByExamId(re.getExamId());
  188. list.forEach(ref -> {
  189. Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
  190. if (faultService.isDisable(f.getFaultId())) {
  191. l.warn("故障{}-Disable", ref.getFaultId());
  192. return;
  193. }
  194. l.info("f.toString() = " + f.toString());
  195. Sim s = simService.selectSimBySimId(re.getSimId());
  196. l.info("s.toString() = " + s.toString());
  197. // check
  198. if (Objects.isNull(f)) {
  199. }
  200. clearOneFault(s, ref, f);
  201. });
  202. }
  203. /**
  204. * Async version.
  205. *
  206. * @param re
  207. */
  208. @Async("tp-comm")
  209. public void clearListFaultByRealExamAsync(RealExam re) {
  210. clearListFaultByRealExam(re);
  211. }
  212. public void clearAll() {
  213. // todo:
  214. simService.listAllEnable().forEach(s -> {
  215. String simType = s.getSimType();
  216. List<Fault> listF = faultService.listAllType3EnableBySimType(simType);
  217. listF.forEach(f -> {
  218. clearOneFault(s, null, f);
  219. });
  220. });
  221. }
  222. /**
  223. * @param s
  224. * @param reF 可以为空,表示不关联考试的。
  225. * @param f
  226. */
  227. public void clearOneFault(Sim s, RealExamFault reF, Fault f) {
  228. // check todo:
  229. //
  230. try {
  231. // step1
  232. SimMsg sm1 = new SimMsg();
  233. String sendMsg1 = buildSendMsgClearFault(s.getSimNum(), f.getBindHardwareMsg());
  234. sm1.setSendMsg(sendMsg1);
  235. String receiveMsg1 = send(sendMsg1, s);
  236. sm1.setReceiveMsg(receiveMsg1);
  237. simReceiveService.clearOneFault(sm1, s, reF, f);
  238. // step2
  239. if (reF != null && realExamFaultService.isState(reF.getRefId(), RealExamFault.REF_STATE_CLEARED)) {
  240. writeOneFault(s, reF, f);
  241. }
  242. } catch (SocketTimeoutException e) {
  243. throw new RuntimeException(e);
  244. } catch (IOException e) {
  245. throw new RuntimeException(e);
  246. }
  247. }
  248. public void writeOneFault(Sim s, RealExamFault ref, Fault f) {
  249. try {
  250. // 下发故障
  251. SimMsg sm1 = new SimMsg();
  252. String sendMsg1 = buildSendMsgWriteFault(s.getSimNum(), f.getBindHardwareMsg());
  253. sm1.setSendMsg(sendMsg1);
  254. String receiveMsg1 = send(sendMsg1, s);
  255. sm1.setReceiveMsg(receiveMsg1);
  256. // todo:
  257. // 读取一次当前电阻代表值作为出题值。
  258. SimMsg sm2 = new SimMsg();
  259. String sendMsg2 = buildSendMsgReadFaultResistance(s.getSimNum(), f.getBindHardwareMsg());
  260. sm2.setSendMsg(sendMsg2);
  261. String receiveMsg2 = send(sendMsg2, s);
  262. sm2.setReceiveMsg(receiveMsg2);
  263. simReceiveService.setFaultQuestionValue(sm2, s, ref, f);
  264. // 修改关联状态。
  265. {
  266. RealExamFault f1 = realExamFaultService.selectRealExamFaultByRefId(ref.getRefId());
  267. f1.setRefState(RealExamFault.REF_STATE_LOOP_READ);
  268. realExamFaultService.updateRealExamFault(f1);
  269. }
  270. } catch (IOException e) {
  271. throw new RuntimeException(e);
  272. }
  273. }
  274. public void readOneFaultResistance(Sim s, RealExamFault reF, Fault f) {
  275. try {
  276. SimMsg sm = new SimMsg();
  277. String sendMsg = buildSendMsgReadFaultResistance(s.getSimNum(), "03");
  278. sm.setSendMsg(sendMsg);
  279. String receiveMsg = send(sendMsg, s);
  280. sm.setReceiveMsg(receiveMsg);
  281. simReceiveService.setFaultAnswerValue(sm, s, reF, f);
  282. } catch (IOException e) {
  283. throw new RuntimeException(e);
  284. }
  285. }
  286. public void test() {
  287. try {
  288. {
  289. String sendMsg = buildSendMsgReadFaultResistance("01", "04");
  290. send(sendMsg, null);
  291. }
  292. {
  293. String sendMsg = buildSendMsgReadFaultResistance("01", "05");
  294. send(sendMsg, null);
  295. }
  296. {
  297. String sendMsg = buildSendMsgReadFaultResistance("01", "06");
  298. send(sendMsg, null);
  299. }
  300. } catch (IOException e) {
  301. throw new RuntimeException(e);
  302. }
  303. }
  304. /**
  305. * 设备类型读取
  306. *
  307. * @param simNum sim.sim_num
  308. */
  309. public String buildSendMsgReadSimType(final String simNum) {
  310. return buildSendMsg(simNum, CMD_READ_TYPE, CMD_ID_GET_SN);
  311. }
  312. /**
  313. * 故障下发
  314. *
  315. * @param simNum sim.sim_num
  316. * @param bindHardwareMsg fault.bind_hardware_msg
  317. */
  318. public String buildSendMsgWriteFault(final String simNum, final String bindHardwareMsg) {
  319. return buildSendMsg(simNum, CMD_SET_FAULT, bindHardwareMsg);
  320. }
  321. /**
  322. * 状态读取
  323. *
  324. * @param simNum sim.sim_num
  325. * @param bindHardwareMsg fault.bind_hardware_msg
  326. */
  327. public String buildSendMsgReadFaultResistance(final String simNum, final String bindHardwareMsg) {
  328. return buildSendMsg(simNum, CMD_READ_FAULT_RESISTANCE, bindHardwareMsg);
  329. }
  330. /**
  331. * 故障清清除
  332. *
  333. * @param simNum sim.sim_num
  334. * @param bindHardwareMsg fault.bind_hardware_msg
  335. */
  336. public String buildSendMsgClearFault(final String simNum, final String bindHardwareMsg) {
  337. return buildSendMsg(simNum, CMD_CLEAR_FAULT, bindHardwareMsg);
  338. }
  339. public String buildSendMsg(final String simNum, final String cmd, final String cmdId) {
  340. return buildSendMsg(simNum, cmd, cmdId, CMD_DATA_PLACE_HOLDER);
  341. }
  342. public String buildSendMsg(final String simNum, final String cmd, final String cmdId, final String data) {
  343. if (StringUtils.isEmpty(simNum) || StringUtils.isEmpty(cmd) || StringUtils.isEmpty(cmdId) || StringUtils.isEmpty(data)) {
  344. throw new IllegalArgumentException("buildSendMsg isEmpty");
  345. }
  346. if (simNum.length() != LENGTH_2) {
  347. throw new IllegalArgumentException("buildSendMsg length error");
  348. }
  349. if (cmd.length() != LENGTH_2) {
  350. throw new IllegalArgumentException("buildSendMsg length error");
  351. }
  352. if (cmdId.length() != LENGTH_2) {
  353. throw new IllegalArgumentException("buildSendMsg length error");
  354. }
  355. if (data.length() != LENGTH_8) {
  356. throw new IllegalArgumentException("buildSendMsg length error");
  357. }
  358. StringBuffer m = new StringBuffer();
  359. m.append(PREFIX);
  360. m.append(simNum);
  361. m.append(ORN_SEND);
  362. m.append(cmd);
  363. m.append(cmdId);
  364. m.append(data);
  365. m.append(SUFFIX);
  366. final String mFinal = m.toString();
  367. if (mFinal.length() != LENGTH_20) {
  368. throw new IllegalArgumentException("buildSendMsg length error");
  369. }
  370. return mFinal;
  371. }
  372. /**
  373. * send hex message
  374. *
  375. * @param sendMsg
  376. * @param s 可以为空,更新最后发送/接收时间 用。
  377. * @return
  378. */
  379. public synchronized String send(final String sendMsg, final Sim s) throws IOException {
  380. l.info("sendMsg = " + sendMsg);
  381. String receiveMsg = null;
  382. if (cachedSocket == null) {
  383. openSocket();
  384. }
  385. InputStream is = cachedSocket.getInputStream();
  386. OutputStream os = cachedSocket.getOutputStream();
  387. os.write(hexStrToByteArrs(sendMsg));
  388. if (s != null) {
  389. simService.updateLastSentTime(s);
  390. }
  391. byte[] buffer = new byte[1024];
  392. int length = is.read(buffer);
  393. StringBuffer sbHex = new StringBuffer();
  394. for (int i = 0; i < length; i++) {
  395. sbHex.append(String.format("%02X", buffer[i]));
  396. }
  397. receiveMsg = sbHex.toString();
  398. l.info("receiveMsg = {}", receiveMsg);
  399. if (!checkReceiveMsg(receiveMsg)) {
  400. // todo:
  401. l.warn("checkReceiveMsg fail receiveMsg = {}", receiveMsg);
  402. return "";
  403. }
  404. if (s != null) {
  405. simService.updateLastReceivedTime(s);
  406. }
  407. return receiveMsg;
  408. }
  409. public void openSocket() throws IOException {
  410. if (cachedSocket == null) {
  411. cachedSocket = new Socket(IP, PORT);
  412. // setSoTimeout
  413. // cachedSocket.setSoTimeout(1000);
  414. }
  415. }
  416. /**
  417. * todo:异常精细处理
  418. *
  419. * @throws IOException
  420. */
  421. public void closeSocket() throws IOException {
  422. if (cachedSocket != null) {
  423. cachedSocket.close();
  424. }
  425. cachedSocket = null;
  426. }
  427. public byte[] hexStrToByteArrs(String hexString) {
  428. // if (StringUtils.isEmpty(hexString)) {
  429. // return null;
  430. // }
  431. hexString = hexString.replaceAll(" ", "");
  432. int len = hexString.length();
  433. int index = 0;
  434. byte[] bytes = new byte[len / 2];
  435. while (index < len) {
  436. String sub = hexString.substring(index, index + 2);
  437. bytes[index / 2] = (byte) Integer.parseInt(sub, 16);
  438. index += 2;
  439. }
  440. return bytes;
  441. }
  442. /**
  443. * ping
  444. *
  445. * @param ipV4
  446. * @return
  447. * @throws IOException
  448. */
  449. public boolean isReachable(String ipV4) throws IOException {
  450. InetAddress ia = InetAddress.getByName(ipV4);
  451. return ia.isReachable(sConfig.getGatewayReachableTimeout());
  452. }
  453. /**
  454. * check receiveMsg
  455. *
  456. * @param receiveMsg
  457. * @return
  458. */
  459. public boolean checkReceiveMsg(String receiveMsg) {
  460. if (StringUtils.isEmpty(receiveMsg)) {
  461. return false;
  462. }
  463. if (receiveMsg.length() != CommSendService.Const.LENGTH_20) {
  464. return false;
  465. }
  466. final String orn = StringUtils.substring(receiveMsg, 4, 6);
  467. if (!CommSendService.Const.ORN_RECEIVE.equals(orn)) {
  468. return false;
  469. }
  470. if (!StringUtils.startsWith(receiveMsg, CommSendService.Const.PREFIX)) {
  471. return false;
  472. }
  473. if (!StringUtils.endsWith(receiveMsg, CommSendService.Const.SUFFIX)) {
  474. return false;
  475. }
  476. return true;
  477. }
  478. }