huang
2025-11-20 366ba040d2447bacd3455299425e3166f1f992bb
mes-processes/mes-plcSend/src/main/java/com/mes/service/PlcTestWriteService.java
@@ -7,8 +7,6 @@
import com.mes.device.entity.DeviceConfig;
import com.mes.device.service.DeviceConfigService;
import com.mes.device.util.ConfigJsonHelper;
import com.mes.entity.PlcBaseData;
import com.mes.entity.PlcAddress;
import com.mes.service.PlcDynamicDataService;
import com.mes.s7.enhanced.EnhancedS7Serializer;
import lombok.extern.slf4j.Slf4j;
@@ -16,13 +14,17 @@
import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
 * PLC测试写入服务
 * 模拟PLC行为,向PLC写入测试数据,用于测试MES程序
 *
 * 基于DeviceConfig的新API,用于模拟PLC行为进行测试
 *
 * 推荐使用:DevicePlcOperationService(生产环境)
 * 
 * @author huang
 * @date 2025/10/29
@@ -30,9 +32,6 @@
@Slf4j
@Service
public class PlcTestWriteService {
    @Resource
    private PlcAddressService plcAddressService;
    
    @Resource
    private DeviceConfigService deviceConfigService;
@@ -46,310 +45,10 @@
    private static final int ON = 1;
    private static final int OFF = 0;
    
    // 当前使用的项目标识
    private String currentProjectId = "vertical";
    // 缓存不同项目的S7Serializer实例
    // 缓存不同设备的S7Serializer实例
    private final ConcurrentMap<String, EnhancedS7Serializer> serializerCache = new ConcurrentHashMap<>();
    /**
     * 模拟PLC发送请求字(触发MES任务下发)
     */
    public boolean simulatePlcRequest() {
        return simulatePlcRequest(currentProjectId);
    }
    /**
     * 模拟PLC发送请求字(触发MES任务下发)- 支持指定项目
     */
    public boolean simulatePlcRequest(String projectId) {
        try {
            PlcAddress config = plcAddressService.getProjectConfigWithMapping(projectId);
            if (config == null) {
                log.error("项目配置不存在: projectId={}", projectId);
                return false;
            }
            EnhancedS7Serializer s7Serializer = getSerializerForProject(projectId, config);
            if (s7Serializer == null) {
                log.error("无法创建S7Serializer: projectId={}", projectId);
                return false;
            }
            return simulatePlcRequestInternal(projectId, config, s7Serializer);
        } catch (Exception e) {
            log.error("模拟PLC请求字失败", e);
            return false;
        }
    }
    private boolean simulatePlcRequestInternal(String projectId, PlcAddress config, EnhancedS7Serializer s7Serializer) throws Exception {
        PlcBaseData currentData = s7Serializer.read(PlcBaseData.class, config.getDbArea(), config.getBeginIndex());
        if (currentData == null) {
            log.error("读取PLC数据失败,返回null: projectId={}, dbArea={}, beginIndex={}",
                    projectId, config.getDbArea(), config.getBeginIndex());
            return false;
        }
        if (currentData.getOnlineState() == OFF) {
            log.info("当前PLC联机模式为0,停止联机");
            return false;
        } else if (currentData.getPlcReport() == ON) {
            log.info("当前上片PLC汇报字为1,重置为0");
            currentData.setPlcReport(OFF);
        }
        currentData.setPlcRequest(ON);
        s7Serializer.write(currentData, config.getDbArea(), config.getBeginIndex());
        log.info("模拟PLC发送请求字成功:plcRequest=1, projectId={}, dbArea={}, beginIndex={}",
                projectId, config.getDbArea(), config.getBeginIndex());
        return true;
    }
    /**
     * 模拟PLC任务完成汇报
     */
    public boolean simulatePlcReport() {
        return simulatePlcReport(currentProjectId);
    }
    /**
     * 模拟PLC任务完成汇报 - 支持指定项目
     */
    public boolean simulatePlcReport(String projectId) {
        try {
            // 获取项目配置(数据库实体)
            PlcAddress config = plcAddressService.getProjectConfigWithMapping(projectId);
            if (config == null) {
                log.error("项目配置不存在: projectId={}", projectId);
                return false;
            }
            // 获取对应的S7Serializer
            EnhancedS7Serializer s7Serializer = getSerializerForProject(projectId, config);
            if (s7Serializer == null) {
                log.error("无法创建S7Serializer: projectId={}", projectId);
                return false;
            }
            return simulatePlcReportInternal(projectId, config, s7Serializer);
        } catch (Exception e) {
            log.error("模拟PLC任务完成汇报失败", e);
            return false;
        }
    }
    private boolean simulatePlcReportInternal(String projectId, PlcAddress config, EnhancedS7Serializer s7Serializer) throws Exception {
        PlcBaseData currentData = s7Serializer.read(PlcBaseData.class, config.getDbArea(), config.getBeginIndex());
        if (currentData == null) {
            log.error("读取PLC数据失败,返回null: projectId={}, dbArea={}, beginIndex={}",
                    projectId, config.getDbArea(), config.getBeginIndex());
            return false;
        }
        currentData.setPlcReport(ON);
        currentData.setPlcRequest(OFF);
        currentData.setMesGlassCount(10);
        s7Serializer.write(currentData, config.getDbArea(), config.getBeginIndex());
        log.info("模拟PLC任务完成汇报:plcReport=1, mesGlassCount=10, projectId={}, dbArea={}, beginIndex={}",
                projectId, config.getDbArea(), config.getBeginIndex());
        return true;
    }
    /**
     * 模拟PLC发送联机状态
     */
    public boolean simulateOnlineStatus(int onlineState) {
        return simulateOnlineStatus(onlineState, currentProjectId);
    }
    /**
     * 模拟PLC发送联机状态 - 支持指定项目
     */
    public boolean simulateOnlineStatus(int onlineState, String projectId) {
        try {
            // 获取项目配置(数据库实体)
            PlcAddress config = plcAddressService.getProjectConfigWithMapping(projectId);
            if (config == null) {
                log.error("项目配置不存在: projectId={}", projectId);
                return false;
            }
            // 获取对应的S7Serializer
            EnhancedS7Serializer s7Serializer = getSerializerForProject(projectId, config);
            if (s7Serializer == null) {
                log.error("无法创建S7Serializer: projectId={}", projectId);
                return false;
            }
            return simulateOnlineStatusInternal(onlineState, projectId, config, s7Serializer);
        } catch (Exception e) {
            log.error("模拟PLC联机状态失败", e);
            return false;
        }
    }
    private boolean simulateOnlineStatusInternal(int onlineState, String projectId, PlcAddress config, EnhancedS7Serializer s7Serializer) throws Exception {
        PlcBaseData currentData = s7Serializer.read(PlcBaseData.class, config.getDbArea(), config.getBeginIndex());
        if (currentData == null) {
            log.error("读取PLC数据失败,返回null: projectId={}, dbArea={}, beginIndex={}",
                    projectId, config.getDbArea(), config.getBeginIndex());
            return false;
        }
        currentData.setOnlineState(onlineState);
        s7Serializer.write(currentData, config.getDbArea(), config.getBeginIndex());
        log.info("模拟PLC联机状态:onlineState={}, projectId={}, dbArea={}, beginIndex={}",
                onlineState, projectId, config.getDbArea(), config.getBeginIndex());
        return true;
    }
    /**
     * 重置PLC所有状态
     */
    public boolean resetPlc() {
        return resetPlc(currentProjectId);
    }
    /**
     * 重置PLC所有状态 - 支持指定项目
     */
    public boolean resetPlc(String projectId) {
        try {
            // 获取项目配置(数据库实体)
            PlcAddress config = plcAddressService.getProjectConfigWithMapping(projectId);
            if (config == null) {
                log.error("项目配置不存在: projectId={}", projectId);
                return false;
            }
            EnhancedS7Serializer s7Serializer = getSerializerForProject(projectId, config);
            if (s7Serializer == null) {
                log.error("无法创建S7Serializer: projectId={}", projectId);
                return false;
            }
            return resetPlcInternal(projectId, config, s7Serializer);
        } catch (Exception e) {
            log.error("重置PLC状态失败", e);
            return false;
        }
    }
    private boolean resetPlcInternal(String projectId, PlcAddress config, EnhancedS7Serializer s7Serializer) throws Exception {
        PlcBaseData resetData = new PlcBaseData();
        resetData.setPlcRequest(OFF);
        resetData.setPlcReport(OFF);
        resetData.setMesSend(OFF);
        resetData.setMesConfirm(OFF);
        resetData.setOnlineState(ON);
        resetData.setMesGlassCount(0);
        resetData.setAlarmInfo(OFF);
        s7Serializer.write(resetData, config.getDbArea(), config.getBeginIndex());
        log.info("PLC状态已重置, projectId={}, dbArea={}, beginIndex={}",
                projectId, config.getDbArea(), config.getBeginIndex());
        return true;
    }
    /**
     * 读取PLC当前状态
     */
    public PlcBaseData readPlcStatus() {
        return readPlcStatus(currentProjectId);
    }
    /**
     * 读取PLC当前状态 - 支持指定项目
     */
    public PlcBaseData readPlcStatus(String projectId) {
        try {
            // 获取项目配置(数据库实体)
            PlcAddress config = plcAddressService.getProjectConfigWithMapping(projectId);
            if (config == null) {
                log.error("项目配置不存在: projectId={}", projectId);
                return null;
            }
            EnhancedS7Serializer s7Serializer = getSerializerForProject(projectId, config);
            if (s7Serializer == null) {
                log.error("无法创建S7Serializer: projectId={}", projectId);
                return null;
            }
            return readPlcStatusInternal(projectId, config, s7Serializer);
        } catch (Exception e) {
            log.error("读取PLC状态失败", e);
            return null;
        }
    }
    private PlcBaseData readPlcStatusInternal(String projectId, PlcAddress config, EnhancedS7Serializer s7Serializer) throws Exception {
        PlcBaseData data = s7Serializer.read(PlcBaseData.class, config.getDbArea(), config.getBeginIndex());
        if (data == null) {
            log.error("读取PLC状态返回null: projectId={}, dbArea={}, beginIndex={}",
                    projectId, config.getDbArea(), config.getBeginIndex());
        }
        return data;
    }
    /**
     * 设置当前项目标识
     */
    public void setCurrentProjectId(String projectId) {
        this.currentProjectId = projectId;
    }
    /**
     * 获取当前项目标识
     */
    public String getCurrentProjectId() {
        return this.currentProjectId;
    }
    /**
     * 获取项目对应的S7Serializer实例
     * 如果不存在,则创建一个新的实例并缓存
     *
     * @param projectId 项目标识
     * @param config 项目配置
     * @return S7Serializer实例
     */
    private EnhancedS7Serializer getSerializerForProject(String projectId, PlcAddress config) {
        return serializerCache.computeIfAbsent(projectId, id -> {
            // 解析PLC类型
            EPlcType plcType = EPlcType.S1200; // 默认值
            if (config != null && config.getPlcType() != null) {
                try {
                    plcType = EPlcType.valueOf(config.getPlcType());
                } catch (IllegalArgumentException e) {
                    log.warn("未知的PLC类型: {}, 使用默认类型 S1200", config.getPlcType());
                }
            }
            // 创建S7PLC实例
            String plcIp = (config != null && config.getPlcIp() != null) ? config.getPlcIp() : "192.168.10.21";
            S7PLC s7Plc = new S7PLC(plcType, plcIp);
            // 创建并返回EnhancedS7Serializer实例
            return EnhancedS7Serializer.newInstance(s7Plc);
        });
    }
    /**
     * 清除指定项目的S7Serializer缓存
     *
     * @param projectId 项目标识
     */
    public void clearSerializerCache(String projectId) {
        serializerCache.remove(projectId);
        log.info("已清除项目 {} 的S7Serializer缓存", projectId);
    }
    /**
     * 清除所有S7Serializer缓存
     */
    public void clearAllSerializerCache() {
        serializerCache.clear();
        log.info("已清除所有S7Serializer缓存");
    }
    // ==================== 基于DeviceConfig的新API(推荐使用) ====================
    
    /**
     * 根据设备ID模拟PLC发送请求字
@@ -364,10 +63,73 @@
            return false;
        }
        try {
            String projectId = resolveProjectId(device);
            PlcAddress config = buildPlcAddressFromDevice(device);
            EnhancedS7Serializer s7Serializer = getSerializerForDevice(device);
            return simulatePlcRequestInternal(projectId, config, s7Serializer);
            if (s7Serializer == null) {
                log.error("获取S7Serializer失败: deviceId={}", deviceId);
                return false;
            }
            // 使用PlcDynamicDataService读取数据(支持addressMapping)
            Map<String, Object> currentData = plcDynamicDataService.readAllPlcData(device, s7Serializer);
            if (currentData == null || currentData.isEmpty()) {
                log.error("读取PLC数据失败,返回空: deviceId={}", deviceId);
                return false;
            }
            // 检查联机状态
            Object onlineStateObj = currentData.get("onlineState");
            Integer onlineState = null;
            if (onlineStateObj != null) {
                if (onlineStateObj instanceof Number) {
                    onlineState = ((Number) onlineStateObj).intValue();
                } else {
                    try {
                        String strValue = String.valueOf(onlineStateObj);
                        if (!strValue.isEmpty() && !"null".equalsIgnoreCase(strValue)) {
                            onlineState = Integer.parseInt(strValue);
                        }
                    } catch (NumberFormatException e) {
                        log.warn("解析onlineState失败: deviceId={}, value={}", deviceId, onlineStateObj, e);
                    }
                }
            }
            if (onlineState != null && onlineState == OFF) {
                log.info("当前PLC联机模式为0,停止联机: deviceId={}", deviceId);
                return false;
            }
            // 检查汇报字,如果为1则重置为0
            Object plcReportObj = currentData.get("plcReport");
            Integer plcReport = null;
            if (plcReportObj != null) {
                if (plcReportObj instanceof Number) {
                    plcReport = ((Number) plcReportObj).intValue();
                } else {
                    try {
                        String strValue = String.valueOf(plcReportObj);
                        if (!strValue.isEmpty() && !"null".equalsIgnoreCase(strValue)) {
                            plcReport = Integer.parseInt(strValue);
                        }
                    } catch (NumberFormatException e) {
                        log.warn("解析plcReport失败: deviceId={}, value={}", deviceId, plcReportObj, e);
                    }
                }
            }
            if (plcReport != null && plcReport == ON) {
                log.info("当前上片PLC汇报字为1,重置为0: deviceId={}", deviceId);
                currentData.put("plcReport", OFF);
            }
            // 设置请求字为1
            currentData.put("plcRequest", ON);
            // 使用PlcDynamicDataService写入数据
            plcDynamicDataService.writePlcData(device, currentData, s7Serializer);
            log.info("模拟PLC发送请求字成功:plcRequest=1, deviceId={}", deviceId);
            return true;
        } catch (Exception e) {
            log.error("根据设备模拟PLC请求字失败: deviceId={}", deviceId, e);
            return false;
@@ -387,10 +149,29 @@
            return false;
        }
        try {
            String projectId = resolveProjectId(device);
            PlcAddress config = buildPlcAddressFromDevice(device);
            EnhancedS7Serializer s7Serializer = getSerializerForDevice(device);
            return simulatePlcReportInternal(projectId, config, s7Serializer);
            if (s7Serializer == null) {
                log.error("获取S7Serializer失败: deviceId={}", deviceId);
                return false;
            }
            // 使用PlcDynamicDataService读取数据
            Map<String, Object> currentData = plcDynamicDataService.readAllPlcData(device, s7Serializer);
            if (currentData == null || currentData.isEmpty()) {
                log.error("读取PLC数据失败,返回空: deviceId={}", deviceId);
                return false;
            }
            // 设置汇报字为1,请求字清0
            currentData.put("plcReport", ON);
            currentData.put("plcRequest", OFF);
            currentData.put("mesGlassCount", 10);
            // 使用PlcDynamicDataService写入数据
            plcDynamicDataService.writePlcData(device, currentData, s7Serializer);
            log.info("模拟PLC任务完成汇报:plcReport=1, mesGlassCount=10, deviceId={}", deviceId);
            return true;
        } catch (Exception e) {
            log.error("根据设备模拟PLC汇报失败: deviceId={}", deviceId, e);
            return false;
@@ -410,10 +191,27 @@
            return false;
        }
        try {
            String projectId = resolveProjectId(device);
            PlcAddress config = buildPlcAddressFromDevice(device);
            EnhancedS7Serializer s7Serializer = getSerializerForDevice(device);
            return resetPlcInternal(projectId, config, s7Serializer);
            if (s7Serializer == null) {
                log.error("获取S7Serializer失败: deviceId={}", deviceId);
                return false;
            }
            // 构建重置数据
            Map<String, Object> resetData = new HashMap<>();
            resetData.put("plcRequest", OFF);
            resetData.put("plcReport", OFF);
            resetData.put("mesSend", OFF);
            resetData.put("mesConfirm", OFF);
            resetData.put("onlineState", ON);
            resetData.put("mesGlassCount", 0);
            resetData.put("alarmInfo", OFF);
            // 使用PlcDynamicDataService写入数据
            plcDynamicDataService.writePlcData(device, resetData, s7Serializer);
            log.info("PLC状态已重置, deviceId={}", deviceId);
            return true;
        } catch (Exception e) {
            log.error("根据设备重置PLC状态失败: deviceId={}", deviceId, e);
            return false;
@@ -433,15 +231,14 @@
            return null;
        }
        try {
            String projectId = resolveProjectId(device);
            PlcAddress config = buildPlcAddressFromDevice(device);
            EnhancedS7Serializer s7Serializer = getSerializerForDevice(device);
            PlcBaseData data = readPlcStatusInternal(projectId, config, s7Serializer);
            if (data == null) {
            if (s7Serializer == null) {
                log.error("获取S7Serializer失败: deviceId={}", deviceId);
                return null;
            }
            String json = objectMapper.writeValueAsString(data);
            return objectMapper.readValue(json, MAP_TYPE);
            // 使用PlcDynamicDataService读取所有数据(支持addressMapping)
            Map<String, Object> data = plcDynamicDataService.readAllPlcData(device, s7Serializer);
            return data;
        } catch (Exception e) {
            log.error("读取设备PLC状态失败: deviceId={}", deviceId, e);
            return null;
@@ -463,16 +260,17 @@
        }
        
        try {
            // 从设备配置中获取项目标识
            String projectId = resolveProjectId(device);
            // 获取对应的S7Serializer(使用设备配置)
            EnhancedS7Serializer s7Serializer = getSerializerForDevice(device);
            if (s7Serializer == null) {
                log.error("获取S7Serializer失败: deviceId={}", deviceId);
                return false;
            }
            
            // 使用动态数据服务写入字段(基于DeviceConfig)
            plcDynamicDataService.writePlcData(device, fieldValues, s7Serializer);
            
            log.info("写入PLC字段成功: deviceId={}, projectId={}, fields={}", deviceId, projectId, fieldValues.keySet());
            log.info("写入PLC字段成功: deviceId={}, fields={}", deviceId, fieldValues.keySet());
            return true;
        } catch (Exception e) {
            log.error("写入PLC字段失败: deviceId={}", deviceId, e);
@@ -487,8 +285,25 @@
     * @return S7Serializer实例
     */
    private EnhancedS7Serializer getSerializerForDevice(DeviceConfig device) {
        String cacheKey = "device:" + (device.getId() != null ? device.getId() : resolveProjectId(device));
        if (device == null) {
            log.error("设备配置为空,无法创建S7Serializer");
            return null;
        }
        try {
            String cacheKey;
            if (device.getId() != null) {
                cacheKey = "device:" + device.getId();
            } else {
                try {
                    cacheKey = "device:" + resolveProjectId(device);
                } catch (Exception e) {
                    cacheKey = "device:" + (device.getDeviceCode() != null ? device.getDeviceCode() : "unknown");
                }
            }
        return serializerCache.computeIfAbsent(cacheKey, id -> {
                try {
            // 解析PLC类型(仅取实体字段)
            EPlcType plcType = EPlcType.S1200;
            String plcTypeValue = device.getPlcType();
@@ -511,62 +326,23 @@
            S7PLC s7Plc = new S7PLC(plcType, plcIp);
            
            // 创建并返回EnhancedS7Serializer实例
            return EnhancedS7Serializer.newInstance(s7Plc);
                    EnhancedS7Serializer serializer = EnhancedS7Serializer.newInstance(s7Plc);
                    if (serializer == null) {
                        log.error("创建EnhancedS7Serializer失败: deviceId={}, plcIp={}, plcType={}",
                            device.getId(), plcIp, plcType);
                    }
                    return serializer;
                } catch (Exception e) {
                    log.error("创建S7Serializer异常: deviceId={}", device.getId(), e);
                    return null;
                }
        });
    }
    private PlcAddress buildPlcAddressFromDevice(DeviceConfig device) {
        Map<String, Object> plcConfig = getPlcConfigParams(device);
        String dbArea = plcConfig.get("dbArea") != null ? String.valueOf(plcConfig.get("dbArea")) : "DB12";
        int beginIndex = plcConfig.get("beginIndex") != null ? parseInteger(plcConfig.get("beginIndex")) : 0;
        String plcIp = device.getPlcIp();
        if (plcIp == null || plcIp.isEmpty()) {
            log.warn("设备未配置PLC IP,使用默认 192.168.10.21, deviceId={}", device.getId());
            plcIp = "192.168.10.21";
        }
        String plcType = device.getPlcType();
        if (plcType == null || plcType.isEmpty()) {
            log.warn("设备未配置PLC类型,使用默认S1200, deviceId={}", device.getId());
            plcType = EPlcType.S1200.name();
        }
        String addressMapping = resolveAddressMapping(device);
        PlcAddress config = new PlcAddress();
        config.setProjectId(resolveProjectId(device));
        config.setDbArea(dbArea);
        config.setBeginIndex(beginIndex);
        config.setPlcIp(plcIp);
        config.setPlcType(plcType);
        config.setAddressMapping(addressMapping);
        return config;
    }
    private String resolveAddressMapping(DeviceConfig device) {
        Map<String, Object> mapping = ConfigJsonHelper.parseToMap(device.getConfigJson(), objectMapper);
        if (!mapping.isEmpty()) {
            try {
                return objectMapper.writeValueAsString(mapping);
            } catch (Exception e) {
                log.warn("序列化configJson字段映射失败, deviceId={}", device.getId(), e);
            log.error("获取S7Serializer失败: deviceId={}", device.getId(), e);
            return null;
            }
        }
        Map<String, Object> extraParams = parseExtraParams(device);
        Object addressMapping = extraParams.get("addressMapping");
        if (addressMapping instanceof String) {
            return (String) addressMapping;
        }
        if (addressMapping != null) {
            try {
                return objectMapper.writeValueAsString(addressMapping);
            } catch (Exception e) {
                log.warn("序列化extraParams.addressMapping失败, deviceId={}", device.getId(), e);
            }
        }
        throw new IllegalStateException("设备未配置PLC字段映射, deviceId=" + device.getId());
    }
    private Map<String, Object> parseExtraParams(DeviceConfig device) {
        if (device.getExtraParams() == null || device.getExtraParams().trim().isEmpty()) {