diff --git a/src/main/java/com/iflytop/gd/app/core/BaseCommandHandler.java b/src/main/java/com/iflytop/gd/app/core/BaseCommandHandler.java index 3c1799c..51a77bf 100644 --- a/src/main/java/com/iflytop/gd/app/core/BaseCommandHandler.java +++ b/src/main/java/com/iflytop/gd/app/core/BaseCommandHandler.java @@ -4,9 +4,12 @@ package com.iflytop.gd.app.core; import com.iflytop.gd.common.annotation.CheckedRunnable; import com.iflytop.gd.common.cmd.CommandHandler; +import com.iflytop.gd.common.device.CommandFuture; import com.iflytop.gd.common.utils.LambdaUtil; +import java.util.Arrays; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; public abstract class BaseCommandHandler implements CommandHandler { @@ -14,4 +17,11 @@ public abstract class BaseCommandHandler implements CommandHandler { return CompletableFuture.runAsync(LambdaUtil.unchecked(task)); } + protected void commandWait(CommandFuture... futures) throws Exception { + CompletableFuture[] responseFutures = Arrays.stream(futures) + .map(CommandFuture::getResponseFuture) + .toArray(CompletableFuture[]::new); + CompletableFuture.allOf(responseFutures) + .get(120, TimeUnit.SECONDS); + } } \ No newline at end of file diff --git a/src/main/java/com/iflytop/gd/app/service/cmd/DemoCommand.java b/src/main/java/com/iflytop/gd/app/service/cmd/DemoCommand.java index b50dd18..48b0a8c 100644 --- a/src/main/java/com/iflytop/gd/app/service/cmd/DemoCommand.java +++ b/src/main/java/com/iflytop/gd/app/service/cmd/DemoCommand.java @@ -1,8 +1,12 @@ package com.iflytop.gd.app.service.cmd; +import com.iflytop.gd.app.core.BaseCommandHandler; import com.iflytop.gd.app.model.dto.CmdDTO; import com.iflytop.gd.common.annotation.CommandMapping; import com.iflytop.gd.common.cmd.CommandHandler; +import com.iflytop.gd.common.device.CommandFuture; +import com.iflytop.gd.common.device.DeviceCommand; +import com.iflytop.gd.common.device.DeviceCommandGenerator; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -12,10 +16,15 @@ import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor @CommandMapping("demo_command")//业务指令注解 -public class DemoCommand implements CommandHandler { +public class DemoCommand extends BaseCommandHandler { @Override public void handle(CmdDTO cmdDTO) { log.info("cmdDTO:{}", cmdDTO); + + //XYZ回原点 + DeviceCommand motorXOriginCommand = DeviceCommandGenerator.motorXOrigin(); + DeviceCommand motorYOriginCommand = DeviceCommandGenerator.motorYOrigin(); + DeviceCommand motorZOriginCommand = DeviceCommandGenerator.motorZOrigin(); } } diff --git a/src/main/java/com/iflytop/gd/common/device/CommandFuture.java b/src/main/java/com/iflytop/gd/common/device/CommandFuture.java new file mode 100644 index 0000000..c3154c1 --- /dev/null +++ b/src/main/java/com/iflytop/gd/common/device/CommandFuture.java @@ -0,0 +1,55 @@ +package com.iflytop.gd.common.device; + +import cn.hutool.json.JSONObject; +import lombok.Getter; +import lombok.Setter; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@Setter +@Getter +public class CommandFuture { + /** + * 用于保存response反馈 + */ + private CompletableFuture responseFuture = new CompletableFuture<>(); + + private long startSendTime; + private long endSendTime; + + /** + * 业务指令id + */ + private String cmdId; + /** + * 业务指令code + */ + private String cmdCode; + /** + * 设备指令 + */ + private DeviceCommand deviceCommand; + + /** + * 完成response + */ + public void completeResponse(JSONObject result) { + responseFuture.complete(result); + } + + /** + * 异常完成response + */ + public void completeResponseExceptionally(Throwable ex) { + responseFuture.completeExceptionally(ex); + } + + /** + * 获取response的json + */ + public JSONObject getResponseResult() throws ExecutionException, InterruptedException { + return responseFuture.get(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/iflytop/gd/common/device/CyclicNumberGenerator.java b/src/main/java/com/iflytop/gd/common/device/CyclicNumberGenerator.java new file mode 100644 index 0000000..da0d2b8 --- /dev/null +++ b/src/main/java/com/iflytop/gd/common/device/CyclicNumberGenerator.java @@ -0,0 +1,39 @@ +package com.iflytop.gd.common.device; + +public class CyclicNumberGenerator { + // 饿汉式单例,在类加载时就创建实例 + private static final CyclicNumberGenerator INSTANCE = new CyclicNumberGenerator(); + // 当前生成的数字,初始值为 1 + private int currentNumber = 1; + + // 私有构造函数,防止外部实例化 + private CyclicNumberGenerator() { + } + + // 提供全局访问点获取单例实例 + public static CyclicNumberGenerator getInstance() { + return INSTANCE; + } + + public static void main(String[] args) { + CyclicNumberGenerator generator = CyclicNumberGenerator.getInstance(); + for (int i = 0; i < 4096; i++) { + System.out.println(generator.generateNumber()); + } + } + + /** + * 生成 1 到 255 之间的循环整数 + * + * @return 生成的整数 + */ + public synchronized int generateNumber() { + int result = currentNumber; + // 每次生成后将当前数字加 1 + currentNumber++; + if (currentNumber > 4096) { + currentNumber = 1; + } + return result; + } +} \ No newline at end of file diff --git a/src/main/java/com/iflytop/gd/common/device/DeviceCommand.java b/src/main/java/com/iflytop/gd/common/device/DeviceCommand.java new file mode 100644 index 0000000..12d9c2d --- /dev/null +++ b/src/main/java/com/iflytop/gd/common/device/DeviceCommand.java @@ -0,0 +1,38 @@ +package com.iflytop.gd.common.device; + +import lombok.Data; + +import java.util.Map; + +@Data +public class DeviceCommand { + /** + * 指令ID + */ + private Integer cmdId; + + /** + * 指令名称 + */ + private String cmdName; + + /** + * 指令代码 例如 "device_status_get" + */ + private String cmdCode; + + /** + * 目标设备 + */ + private String device; + + /** + * 执行动作 + */ + private String action; + + /** + * 指令参数 + */ + private Map param; +} diff --git a/src/main/java/com/iflytop/gd/common/device/DeviceCommandGenerator.java b/src/main/java/com/iflytop/gd/common/device/DeviceCommandGenerator.java new file mode 100644 index 0000000..61b0ca5 --- /dev/null +++ b/src/main/java/com/iflytop/gd/common/device/DeviceCommandGenerator.java @@ -0,0 +1,501 @@ +package com.iflytop.gd.common.device; + + +import java.util.HashMap; +import java.util.Map; + +/** + * 生成给设备发送的指令 + */ +public class DeviceCommandGenerator { + + /** + * 全部关闭三通阀 + */ + public static DeviceCommand threeWayValveCloseAll() { + // 上层方法直接取方法注释“全部关闭三通阀” + return threeWayValveControl("close_all", "全部关闭三通阀"); + } + + /** + * 打开三通阀喷嘴管路 + */ + public static DeviceCommand threeWayValveOpenSyringePipeline() { + return threeWayValveControl("open_syringe", "打开三通阀喷嘴管路"); + } + + /** + * 打开三通阀注射器管路 + */ + public static DeviceCommand threeWayValveOpenNozzlePipeline() { + return threeWayValveControl("open_nozzle", "打开三通阀注射器管路"); + } + + /** + * 控制三通阀 + */ + public static DeviceCommand threeWayValveControl(String action, String commandName) { + // 调用中层 controlCmd 时,直接用方法注释固定描述"控制三通阀" + return controlCmd("three_way_valve", action, null, commandName != null ? commandName : "控制三通阀"); + } + + /** + * 关闭清洗阀 + */ + public static DeviceCommand washValveClose() { + return washValveControl("close", "关闭清洗阀"); + } + + /** + * 开启清洗阀 + */ + public static DeviceCommand washValveOpen() { + return washValveControl("open", "开启清洗阀"); + } + + /** + * 控制清洗阀 + */ + public static DeviceCommand washValveControl(String action, String commandName) { + return controlCmd("wash_valve", action, null, commandName != null ? commandName : "控制清洗阀"); + } + + /** + * 关闭喷嘴阀 + */ + public static DeviceCommand nozzleValveClose() { + return nozzleValveControl("close", "关闭喷嘴阀"); + } + + /** + * 开启喷嘴阀 + */ + public static DeviceCommand nozzleValveOpen() { + return nozzleValveControl("open", "开启喷嘴阀"); + } + + /** + * 控制喷嘴阀 + */ + public static DeviceCommand nozzleValveControl(String action, String commandName) { + return controlCmd("nozzle_valve", action, null, commandName != null ? commandName : "控制喷嘴阀"); + } + + /** + * 关闭除湿阀 + */ + public static DeviceCommand dehumidifierValveClose() { + return dehumidifierValveControl("close", "关闭除湿阀"); + } + + /** + * 开启除湿阀 + */ + public static DeviceCommand dehumidifierValveOpen() { + return dehumidifierValveControl("open", "开启除湿阀"); + } + + /** + * 控制除湿阀 + */ + public static DeviceCommand dehumidifierValveControl(String action, String commandName) { + return controlCmd("dehumidifier_valve", action, null, commandName != null ? commandName : "控制除湿阀"); + } + + /** + * 关闭照明灯板 + */ + public static DeviceCommand lightingPanelClose() { + return controlCmd("lighting_panel", "close", null, "关闭照明灯板"); + } + + /** + * 打开照明灯板 + */ + public static DeviceCommand lightingPanelOpen() { + return controlCmd("lighting_panel", "open", null, "打开照明灯板"); + } + + /** + * 控制照明灯板 + */ + public static DeviceCommand lightingPanelControl(String action, String commandName) { + return controlCmd("lighting_panel", action, null, commandName != null ? commandName : "控制照明灯板"); + } + + /** + * 关闭激光 + */ + public static DeviceCommand laserControlClose() { + return laserControl("close", null); + } + + /** + * 打开激光 + * + * @param power 功率[0-100] + */ + public static DeviceCommand laserControlOpen(Double power) { + return laserControl("open", power); + } + + /** + * 控制激光 + * + * @param power 功率[0-100] + */ + public static DeviceCommand laserControl(String action, Double power) { + Map params = new HashMap<>(); + params.put("power", power); + return controlCmd("laser", action, params, "控制激光"); + } + + /** + * 关闭高压 + */ + public static DeviceCommand highVoltageClose() { + return highVoltageControl("close", null); + } + + /** + * 开启高压 + */ + public static DeviceCommand highVoltageOpen(Double voltage) { + return highVoltageControl("open", voltage); + } + + /** + * 控制高压 + */ + public static DeviceCommand highVoltageControl(String action, Double voltage) { + Map params = new HashMap<>(); + params.put("voltage", voltage); + return controlCmd("high_voltage", action, params, "控制高压"); + } + + /** + * 停止推动注射泵 + */ + public static DeviceCommand syringePumpStop() { + return controlCmd("syringe_pump", "stop", null, "停止推动注射泵"); + } + + /** + * 推动移动注射泵 + * + * @param speed 是指注射泵每分钟注射多少微升(volume 最低0.1) + */ + public static DeviceCommand syringePumpStart(String direction, Double speed) { + Map params = new HashMap<>(); + params.put("direction", direction); + params.put("speed", speed); + return controlCmd("syringe_pump", "move", params, "推动移动注射泵"); + } + + /** + * 推动移动注射泵 + * + * @param speed 是指注射泵每分钟注射多少微升(volume 最低0.1) + */ + public static DeviceCommand syringePumpForward(Double speed) { + Map params = new HashMap<>(); + params.put("direction", "forward"); + params.put("speed", speed); + return controlCmd("syringe_pump", "move", params, "推动移动注射泵"); + } + + /** + * 注射泵流速设置 + */ + public static DeviceCommand syringePumpVolumeSet(Double speed) { + Map params = new HashMap<>(); + params.put("speed", speed); + return controlCmd("syringe_pump", "set", params, "注射泵流速设置"); + } + + /** + * 控制注射泵 + */ + public static DeviceCommand syringePumpControl(String action, String forward, Double volume) { + Map params = new HashMap<>(); + params.put("current", forward); + params.put("volume", volume); + return controlCmd("syringe_pump", action, params, "控制注射泵"); + } + + /** + * 获取设备当前湿度 + */ + public static DeviceCommand humidityGet() { + return getInfoCmd("humidity", "获取设备当前湿度"); + } + + /** + * 获取设备当前温度 + */ + public static DeviceCommand temperatureGet() { + return getInfoCmd("temperature", "获取设备当前温度"); + } + + /** + * 推入玻片托盘 + */ + public static DeviceCommand slideTrayIn(Double position, Double speed) { + return motorYPositionSet(position, speed, "推入玻片托盘"); + } + + /** + * 推出玻片托盘 + */ + public static DeviceCommand slideTrayOut(Double position, Double speed) { + return motorYPositionSet(position, speed, "推出玻片托盘"); + } + + /** + * 获得电机XYZ相对原点坐标 + */ + public static DeviceCommand motorXyzPositionGet() { + return getInfoCmd("xyz", "获得电机XYZ相对原点坐标"); + } + + /** + * x轴停止移动 + */ + public static DeviceCommand motorXStop() { + return controlMotorCmd("x", "stop", null, null, null, null, "x轴停止移动"); + } + + /** + * y轴停止移动 + */ + public static DeviceCommand motorYStop() { + return controlMotorCmd("y", "stop", null, null, null, null, "y轴停止移动"); + } + + /** + * z轴停止移动 + */ + public static DeviceCommand motorZStop() { + return controlMotorCmd("z", "stop", null, null, null, null, "z轴停止移动"); + } + + /** + * x轴回原点 + */ + public static DeviceCommand motorXOrigin() { + return controlMotorCmd("x", "origin", null, null, null, null, "x轴回原点"); + } + + /** + * y轴回原点 + */ + public static DeviceCommand motorYOrigin() { + return controlMotorCmd("y", "origin", null, null, null, null, "y轴回原点"); + } + + /** + * z轴回原点 + */ + public static DeviceCommand motorZOrigin() { + return controlMotorCmd("z", "origin", null, null, null, null, "z轴回原点"); + } + + /** + * 移动x轴到指定位置 + */ + public static DeviceCommand motorXPositionSet(Double position) { + return motorXPositionSet(position, null, "移动x轴到指定位置"); + } + + /** + * 移动y轴到指定位置 + */ + public static DeviceCommand motorYPositionSet(Double position) { + return motorYPositionSet(position, null, "移动y轴到指定位置"); + } + + /** + * 移动z轴到指定位置 + */ + public static DeviceCommand motorZPositionSet(Double position) { + return motorZPositionSet(position, null, "移动z轴到指定位置"); + } + + /** + * 移动x轴到指定位置 + */ + public static DeviceCommand motorXPositionSet(Double position, Double speed) { + return motorXPositionSet(position, speed, "移动x轴到指定位置"); + } + + /** + * 移动y轴到指定位置 + */ + public static DeviceCommand motorYPositionSet(Double position, Double speed) { + return motorYPositionSet(position, speed, "移动y轴到指定位置"); + } + + /** + * 移动z轴到指定位置 + */ + public static DeviceCommand motorZPositionSet(Double position, Double speed) { + return motorZPositionSet(position, speed, "移动z轴到指定位置"); + } + + /** + * 移动x轴到指定位置 + */ + private static DeviceCommand motorXPositionSet(Double position, Double speed, String commandName) { + return controlMotorCmd("x", "move", null, "forward", position, speed, commandName); + } + + /** + * 移动y轴到指定位置 + */ + private static DeviceCommand motorYPositionSet(Double position, Double speed, String commandName) { + return controlMotorCmd("y", "move", null, "forward", position, speed, commandName); + } + + /** + * 移动z轴到指定位置 + */ + private static DeviceCommand motorZPositionSet(Double position, Double speed, String commandName) { + return controlMotorCmd("z", "move", null, "forward", position, speed, commandName); + } + + /** + * x电机方向设置 + */ + public static DeviceCommand motorXDirectionSet(String direction) { + return controlMotorCmd("x", "set", null, direction, null, null, "x电机方向设置"); + } + + /** + * y电机方向设置 + */ + public static DeviceCommand motorYDirectionSet(String direction) { + return controlMotorCmd("y", "set", null, direction, null, null, "y电机方向设置"); + } + + /** + * z电机方向设置 + */ + public static DeviceCommand motorZDirectionSet(String direction) { + return controlMotorCmd("z", "set", null, direction, null, null, "z电机方向设置"); + } + + /** + * x轴电机电流设置 + */ + public static DeviceCommand motorXCurrentSet(Double current) { + return controlMotorCmd("x", "set", current, null, null, null, "x轴电机电流设置"); + } + + /** + * y轴电机电流设置 + */ + public static DeviceCommand motorYCurrentSet(Double current) { + return controlMotorCmd("y", "set", current, null, null, null, "y轴电机电流设置"); + } + + /** + * z轴电机电流设置 + */ + public static DeviceCommand motorZCurrentSet(Double current) { + return controlMotorCmd("z", "set", current, null, null, null, "z轴电机电流设置"); + } + + /** + * x轴电机速度设置 + */ + public static DeviceCommand motorXSpeedSet(Double speed) { + return controlMotorCmd("x", "set", null, null, null, speed, "x轴电机速度设置"); + } + + /** + * y轴电机速度设置 + */ + public static DeviceCommand motorYSpeedSet(Double speed) { + return controlMotorCmd("y", "set", null, null, null, speed, "y轴电机速度设置"); + } + + /** + * z轴电机速度设置 + */ + public static DeviceCommand motorZSpeedSet(Double speed) { + return controlMotorCmd("z", "set", null, null, null, speed, "z轴电机速度设置"); + } + + /** + * x轴电机控制 + */ + public static DeviceCommand motorX(String action, Double current, String direction, Double position, Double speed) { + return controlMotorCmd("x", action, current, direction, position, speed, "x轴电机控制"); + } + + /** + * y轴电机控制 + */ + public static DeviceCommand motorY(String action, Double current, String direction, Double position, Double speed) { + return controlMotorCmd("y", action, current, direction, position, speed, "y轴电机控制"); + } + + /** + * z轴电机控制 + */ + public static DeviceCommand motorZ(String action, Double current, String direction, Double position, Double speed) { + return controlMotorCmd("z", action, current, direction, position, speed, "z轴电机控制"); + } + + /** + * 控制设备电机 + */ + public static DeviceCommand controlMotorCmd(String device, String action, Double current, String direction, Double position, Double speed, String commandName) { + if (commandName == null) { + commandName = "控制设备电机"; + } + Map params = new HashMap<>(); + params.put("current", current); + params.put("direction", direction); + params.put("position", position); + params.put("speed", speed); + return deviceCmd("controlMotorCmd", device, action, params, commandName); + } + + /** + * 获取设备整体状态 + */ + public static DeviceCommand overallDeviceStatusGet() { + return getInfoCmd("device", "获取设备整体状态"); + } + + /** + * 设备控制指令包装 + */ + private static DeviceCommand controlCmd(String device, String action, Map params, String commandName) { + return deviceCmd("controlCmd", device, action, params, commandName); + } + + /** + * 获取设备信息指令包装 + */ + private static DeviceCommand getInfoCmd(String device, String commandName) { + return deviceCmd("getInfoCmd", device, "get", null, commandName); + } + + /** + * 设备指令包装 + */ + private static DeviceCommand deviceCmd(String code, String device, String action, Map params, String commandName) { +// int cmdId = CyclicNumberGenerator.getInstance().generateNumber(); + DeviceCommand cmdToDevice = new DeviceCommand(); +// cmdToDevice.setCmdId(cmdId); + cmdToDevice.setCmdCode(code); + cmdToDevice.setDevice(device); + cmdToDevice.setAction(action); + cmdToDevice.setParam(params); + cmdToDevice.setCmdName(commandName); + return cmdToDevice; + } +} + diff --git a/src/main/java/com/iflytop/gd/infrastructure/modules/area/LiquidArea.java b/src/main/java/com/iflytop/gd/infrastructure/modules/area/LiquidArea.java index 0d73006..622461a 100644 --- a/src/main/java/com/iflytop/gd/infrastructure/modules/area/LiquidArea.java +++ b/src/main/java/com/iflytop/gd/infrastructure/modules/area/LiquidArea.java @@ -7,4 +7,5 @@ import org.springframework.stereotype.Component; */ @Component public class LiquidArea { + } diff --git a/src/main/java/com/iflytop/gd/infrastructure/modules/area/RailArmArea.java b/src/main/java/com/iflytop/gd/infrastructure/modules/area/RailArmArea.java index 9a7e662..108ece3 100644 --- a/src/main/java/com/iflytop/gd/infrastructure/modules/area/RailArmArea.java +++ b/src/main/java/com/iflytop/gd/infrastructure/modules/area/RailArmArea.java @@ -7,4 +7,5 @@ import org.springframework.stereotype.Component; */ @Component public class RailArmArea { + } diff --git a/src/main/java/com/iflytop/gd/infrastructure/repository/DeviceFactory.java b/src/main/java/com/iflytop/gd/infrastructure/repository/DeviceFactory.java deleted file mode 100644 index fed68bd..0000000 --- a/src/main/java/com/iflytop/gd/infrastructure/repository/DeviceFactory.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.iflytop.gd.infrastructure.repository; - -import com.iflytop.gd.infrastructure.devices.physical.PhysicalStepMotor; -import com.iflytop.gd.infrastructure.devices.virtual.VirtualStepMotor; -import com.iflytop.gd.infrastructure.drivers.ModuleId; -import com.iflytop.gd.system.devices.StepMotor; -import com.iflytop.gd.system.drivers.CommandBus; -import com.iflytop.gd.system.constants.SystemMode; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -@RequiredArgsConstructor -@Component -public class DeviceFactory { - private final CommandBus commandBus; - public StepMotor createStepMotor(SystemMode systemMode, ModuleId moduleId) { - if (SystemMode.VIRTUAL.equals(systemMode)) { - return new VirtualStepMotor(moduleId); - } - - if (SystemMode.PHYSICAL.equals(systemMode)) { - return new PhysicalStepMotor(moduleId, commandBus); - } - - throw new IllegalArgumentException("Unsupported system mode: " + systemMode); - } -} diff --git a/src/main/java/com/iflytop/gd/infrastructure/repository/DeviceStrategyFactory.java b/src/main/java/com/iflytop/gd/infrastructure/repository/DeviceStrategyFactory.java new file mode 100644 index 0000000..4b5c59b --- /dev/null +++ b/src/main/java/com/iflytop/gd/infrastructure/repository/DeviceStrategyFactory.java @@ -0,0 +1,28 @@ +package com.iflytop.gd.infrastructure.repository; + +import com.iflytop.gd.system.drivers.CommandBus; +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class DeviceStrategyFactory { + private final ApplicationContext ctx; + private final CommandBus commandBus; + + /** + * @param type 接口 Class 对象,如 ColdTray.class + * @param beanName 在 @Component 中定义的名称,如 "coldTrayA" + */ + public T getStrategy(Class type, String beanName) { + Map beans = ctx.getBeansOfType(type); + T strategy = beans.get(beanName); + if (strategy == null) { + throw new IllegalArgumentException("No bean named '" + beanName + "' for type " + type.getSimpleName()); + } + return strategy; + } +}