石墨消解仪后端服务
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.

180 lines
7.9 KiB

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