加酸仪(java版本)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
7.7 KiB

2 weeks ago
  1. package com.iflytop.handacid.app.service;
  2. import cn.hutool.json.JSONObject;
  3. import cn.hutool.json.JSONUtil;
  4. import com.iflytop.handacid.app.common.constant.CommandStatus;
  5. import com.iflytop.handacid.app.core.command.CommandFuture;
  6. import com.iflytop.handacid.app.core.command.CyclicNumberGenerator;
  7. import com.iflytop.handacid.app.core.command.DeviceCommand;
  8. import com.iflytop.handacid.app.core.event.VirtualDeviceCmdResponseEvent;
  9. import com.iflytop.handacid.app.core.state.DeviceState;
  10. import com.iflytop.handacid.app.websocket.server.DebugGenerator;
  11. import com.iflytop.handacid.app.websocket.server.WebSocketSender;
  12. import com.iflytop.handacid.hardware.HardwareService;
  13. import jakarta.annotation.PostConstruct;
  14. import lombok.RequiredArgsConstructor;
  15. import lombok.extern.slf4j.Slf4j;
  16. import org.springframework.context.ApplicationEventPublisher;
  17. import org.springframework.stereotype.Service;
  18. import java.util.ArrayList;
  19. import java.util.List;
  20. import java.util.concurrent.BlockingQueue;
  21. import java.util.concurrent.ConcurrentHashMap;
  22. import java.util.concurrent.ConcurrentMap;
  23. import java.util.concurrent.LinkedBlockingQueue;
  24. @Slf4j
  25. @Service
  26. @RequiredArgsConstructor
  27. public class DeviceCommandService {
  28. private final HardwareService hardwareService;
  29. private final WebSocketSender webSocketService;
  30. private final DeviceState deviceState;
  31. private final ApplicationEventPublisher publisher;
  32. /**
  33. * 需要等待加液区空闲的龙门架机械臂指令
  34. */
  35. private final ConcurrentMap<Integer, CommandFuture> sendCommandFutureMap = new ConcurrentHashMap<>();
  36. private final BlockingQueue<CommandFuture[]> gantryCommandQueue = new LinkedBlockingQueue<>();
  37. @PostConstruct
  38. private void initExecutorThread() {
  39. new Thread(this::executeCommands).start();
  40. }
  41. private void executeCommands() {
  42. while (true) {
  43. try {
  44. CommandFuture[] commandFutureArray = gantryCommandQueue.take();
  45. for (CommandFuture commandFuture : commandFutureArray) {
  46. executeCommand(commandFuture);
  47. }
  48. } catch (Exception e) {
  49. Thread.currentThread().interrupt();
  50. }
  51. }
  52. }
  53. public synchronized CommandFuture[] sendCommandGantryQueue(DeviceCommand... deviceCommandBundles) {
  54. return sendCommandGantryQueue(null, null, deviceCommandBundles);
  55. }
  56. public synchronized CommandFuture[] sendCommandGantryQueue(String cmdId, String cmdCode, DeviceCommand... deviceCommands) {
  57. List<CommandFuture> commandFutureList = new ArrayList<>();
  58. for (DeviceCommand deviceCommand : deviceCommands) {
  59. commandFutureList.add(createDeviceCommandFuture(cmdId, cmdCode, deviceCommand));
  60. }
  61. CommandFuture[] commandFutureArray = commandFutureList.toArray(new CommandFuture[0]);
  62. try {
  63. gantryCommandQueue.put(commandFutureArray);
  64. } catch (Exception e) {
  65. log.error("设备指令入队列失败", e);
  66. throw new RuntimeException(e);
  67. }
  68. return commandFutureArray;
  69. }
  70. /**
  71. * 根据 DeviceCommand 创建 CommandFuture
  72. */
  73. private CommandFuture createDeviceCommandFuture(String cmdId, String cmdCode, DeviceCommand deviceCommand) {
  74. CommandFuture commandFuture = createDeviceCommandFuture(deviceCommand);
  75. commandFuture.setCmdId(cmdId);
  76. commandFuture.setCmdCode(cmdCode);
  77. return commandFuture;
  78. }
  79. /**
  80. * 根据 DeviceCommand 创建 CommandFuture
  81. */
  82. private CommandFuture createDeviceCommandFuture(DeviceCommand deviceCommand) {
  83. CommandFuture commandFuture = new CommandFuture();
  84. commandFuture.setDeviceCommand(deviceCommand);
  85. commandFuture.getResponseFuture().whenComplete((result, ex) -> {
  86. sendCommandFutureMap.remove(deviceCommand.getCmdId());
  87. });
  88. return commandFuture;
  89. }
  90. public void executeCommand(CommandFuture commandFuture) {
  91. int cmdId = CyclicNumberGenerator.getInstance().generateNumber();
  92. commandFuture.getDeviceCommand().setCmdId(cmdId);
  93. sendCommandFutureMap.put(cmdId, commandFuture);
  94. commandFuture.setStartSendTime(System.currentTimeMillis());
  95. if (!deviceState.isVirtual()) {
  96. if (!hardwareService.sendCommand(commandFuture.getDeviceCommand())) {
  97. sendCommandFutureMap.remove(commandFuture.getDeviceCommand().getCmdId());
  98. throw new RuntimeException("向设备发送指令失败");
  99. }
  100. if (commandFuture.getCmdId() != null) {
  101. webSocketService.pushDebug(DebugGenerator.generateJson(commandFuture.getCmdId(), commandFuture.getCmdCode(), CommandStatus.DEVICE_SEND, commandFuture.getDeviceCommand().getDevice() + "_" + commandFuture.getDeviceCommand().getAction() + "指令,已发给设备", commandFuture.getDeviceCommand()));
  102. }
  103. } else {
  104. //虚拟模式
  105. log.info("模拟向设备发送TCP指令:{}", JSONUtil.toJsonStr(commandFuture.getDeviceCommand()));
  106. //模拟反馈
  107. publisher.publishEvent(new VirtualDeviceCmdResponseEvent(this, commandFuture.getDeviceCommand()));
  108. }
  109. }
  110. public CommandFuture sendCommand(DeviceCommand deviceCommand) {
  111. CommandFuture commandFuture = createDeviceCommandFuture(deviceCommand);
  112. executeCommand(commandFuture);
  113. return commandFuture;
  114. }
  115. public CommandFuture sendCommand(String cmdId, String cmdCode, DeviceCommand deviceCommand) {
  116. CommandFuture commandFuture = createDeviceCommandFuture(cmdId, cmdCode, deviceCommand);
  117. executeCommand(commandFuture);
  118. return commandFuture;
  119. }
  120. public void completeCommandResponse(JSONObject deviceResult) {
  121. Integer cmdId = deviceResult.getInt("cmdId");
  122. if (cmdId != null) {
  123. CommandFuture commandFuture = sendCommandFutureMap.get(cmdId);
  124. if (commandFuture != null) {
  125. commandFuture.setEndSendTime(System.currentTimeMillis());
  126. Boolean success = deviceResult.getBool("success"); //数据验证
  127. if (success == null || !success) { //response失败
  128. if (commandFuture.getCmdId() != null) {
  129. webSocketService.pushDebug(DebugGenerator.generateJson(commandFuture.getCmdId(), commandFuture.getCmdCode(), CommandStatus.DEVICE_ERROR,
  130. commandFuture.getDeviceCommand().getDevice() + "_" + commandFuture.getDeviceCommand().getAction() + "指令,设备response错误,耗时:" + (commandFuture.getEndSendTime() - commandFuture.getStartSendTime()), deviceResult));
  131. }
  132. commandFuture.completeResponseExceptionally(new RuntimeException("response失败:" + deviceResult));
  133. } else {
  134. if (commandFuture.getCmdId() != null) {
  135. webSocketService.pushDebug(DebugGenerator.generateJson(commandFuture.getCmdId(), commandFuture.getCmdCode(), CommandStatus.DEVICE_RESULT,
  136. commandFuture.getDeviceCommand().getDevice() + "_" + commandFuture.getDeviceCommand().getAction() + "指令,设备response正常,耗时:" + (commandFuture.getEndSendTime() - commandFuture.getStartSendTime()), deviceResult));
  137. }
  138. commandFuture.completeResponse(deviceResult);
  139. }
  140. }
  141. }
  142. }
  143. /**
  144. * 取消等待中的future并从map中移除
  145. */
  146. public synchronized void releaseAllCommandFutures() {
  147. for (Integer key : sendCommandFutureMap.keySet()) {
  148. CommandFuture future = sendCommandFutureMap.remove(key);
  149. if (future != null) {
  150. future.getResponseFuture().cancel(true);
  151. }
  152. }
  153. }
  154. }