| | |
| | | import com.mes.device.vo.DevicePlcVO; |
| | | import com.mes.interaction.workstation.base.WorkstationBaseHandler; |
| | | import com.mes.interaction.workstation.config.WorkstationLogicConfig; |
| | | import com.mes.s7.enhanced.EnhancedS7Serializer; |
| | | import com.mes.s7.provider.S7SerializerProvider; |
| | | import com.mes.service.PlcDynamicDataService; |
| | | import com.mes.plc.client.PlcClient; |
| | | import com.mes.plc.factory.PlcClientFactory; |
| | | import com.mes.task.model.TaskExecutionContext; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Component; |
| | |
| | | |
| | | private static final List<String> MES_FIELDS = Arrays.asList("mesSend", "mesGlassId", "mesWidth", "mesHeight", "workLine"); |
| | | |
| | | private final PlcDynamicDataService plcDynamicDataService; |
| | | private final GlassInfoService glassInfoService; |
| | | private final S7SerializerProvider s7SerializerProvider; |
| | | private final PlcClientFactory plcClientFactory; |
| | | |
| | | public HorizontalScannerLogicHandler(DevicePlcOperationService devicePlcOperationService, |
| | | PlcDynamicDataService plcDynamicDataService, |
| | | GlassInfoService glassInfoService, |
| | | S7SerializerProvider s7SerializerProvider) { |
| | | PlcClientFactory plcClientFactory) { |
| | | super(devicePlcOperationService); |
| | | this.plcDynamicDataService = plcDynamicDataService; |
| | | this.glassInfoService = glassInfoService; |
| | | this.s7SerializerProvider = s7SerializerProvider; |
| | | this.plcClientFactory = plcClientFactory; |
| | | this.setPlcClientFactory(plcClientFactory); |
| | | } |
| | | |
| | | @Override |
| | |
| | | String operation, |
| | | Map<String, Object> params, |
| | | Map<String, Object> logicParams) { |
| | | EnhancedS7Serializer serializer = s7SerializerProvider.getSerializer(deviceConfig); |
| | | if (serializer == null) { |
| | | return buildResult(deviceConfig, operation, false, "获取PLC序列化器失败", null); |
| | | PlcClient plcClient = getPlcClient(deviceConfig); |
| | | if (plcClient == null) { |
| | | return buildResult(deviceConfig, operation, false, "获取PLC客户端失败", null); |
| | | } |
| | | |
| | | if ("clearPlc".equalsIgnoreCase(operation) || "reset".equalsIgnoreCase(operation)) { |
| | | return clearPlc(deviceConfig, serializer); |
| | | return clearPlc(deviceConfig, plcClient); |
| | | } |
| | | |
| | | WorkstationLogicConfig config = parseWorkstationConfig(logicParams); |
| | | return executeScan(deviceConfig, config, serializer, params); |
| | | return executeScan(deviceConfig, config, plcClient, params); |
| | | } |
| | | |
| | | private DevicePlcVO.OperationResult executeScan(DeviceConfig deviceConfig, |
| | | WorkstationLogicConfig config, |
| | | EnhancedS7Serializer serializer, |
| | | PlcClient plcClient, |
| | | Map<String, Object> params) { |
| | | try { |
| | | // 从参数中获取玻璃ID(定时器每次只处理一个) |
| | |
| | | } |
| | | |
| | | // 执行单次扫描(定时器会循环调用此方法) |
| | | return executeSingleScan(deviceConfig, config, serializer, inputGlassId, params); |
| | | return executeSingleScan(deviceConfig, config, plcClient, inputGlassId, params); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | log.warn("卧转立扫码等待MES数据被中断, deviceId={}", deviceConfig.getId(), e); |
| | |
| | | */ |
| | | private DevicePlcVO.OperationResult executeSingleScan(DeviceConfig deviceConfig, |
| | | WorkstationLogicConfig config, |
| | | EnhancedS7Serializer serializer, |
| | | PlcClient plcClient, |
| | | String inputGlassId, |
| | | Map<String, Object> params) throws InterruptedException { |
| | | // 1. 写入plcRequest=1和plcGlassId(如果提供了玻璃ID) |
| | | triggerScanRequest(deviceConfig, serializer, inputGlassId); |
| | | triggerScanRequest(deviceConfig, plcClient, inputGlassId); |
| | | |
| | | // 2. 等待MES回写mesSend=1以及玻璃信息 |
| | | Map<String, Object> mesData = waitForMesData(deviceConfig, serializer, config); |
| | | Map<String, Object> mesData = waitForMesData(deviceConfig, plcClient, config); |
| | | if (mesData == null || mesData.isEmpty()) { |
| | | log.error("等待MES写入玻璃信息超时: deviceId={}, timeout={}ms", |
| | | deviceConfig.getId(), config.getScanIntervalMs()); |
| | | // 超时也要清空plcRequest |
| | | clearPlcRequestFields(deviceConfig, serializer); |
| | | clearPlcRequestFields(deviceConfig, plcClient); |
| | | return buildResult(deviceConfig, "scanOnce", false, |
| | | String.format("等待MES写入玻璃信息超时(%dms)", config.getScanIntervalMs()), null); |
| | | } |
| | |
| | | String glassId = parseString(mesData.get("mesGlassId")); |
| | | if (!StringUtils.hasText(glassId)) { |
| | | // MES未提供玻璃ID也要清空plcRequest |
| | | clearPlcRequestFields(deviceConfig, serializer); |
| | | clearPlcRequestFields(deviceConfig, plcClient); |
| | | return buildResult(deviceConfig, "scanOnce", false, "MES写区未提供玻璃ID", null); |
| | | } |
| | | // 读取MES尺寸数据:mesWidth=宽,mesHeight=长 |
| | |
| | | Integer workLine = parseInteger(mesData.get("workLine")); |
| | | |
| | | // 4. 清空plcRequest和plcGlassId(只清除PLC字段) |
| | | clearPlcRequestFields(deviceConfig, serializer); |
| | | clearPlcRequestFields(deviceConfig, plcClient); |
| | | |
| | | // 5. 更新玻璃信息状态:将state从0改为1(已扫码交互) |
| | | boolean updated = glassInfoService.updateGlassStateAfterScan(glassId, rawWidth, rawHeight, workLine); |
| | |
| | | } |
| | | |
| | | private DevicePlcVO.OperationResult clearPlc(DeviceConfig deviceConfig, |
| | | EnhancedS7Serializer serializer) { |
| | | PlcClient plcClient) { |
| | | try { |
| | | // 只清空PLC操作区字段(plcRequest、plcGlassId),不清空MES写区字段 |
| | | Map<String, Object> resetFields = new HashMap<>(); |
| | | resetFields.put("plcRequest", 0); |
| | | resetFields.put("plcGlassId", ""); |
| | | plcDynamicDataService.writePlcData(deviceConfig, resetFields, serializer); |
| | | plcClient.writeData(resetFields); |
| | | return buildResult(deviceConfig, "clearPlc", true, "已清空PLC操作区字段(保留MES写区字段)", null); |
| | | } catch (Exception e) { |
| | | log.error("卧转立扫码清空PLC失败, deviceId={}", deviceConfig.getId(), e); |
| | |
| | | /** |
| | | * 触发MES请求:写入plcRequest=1和plcGlassId(如果提供了玻璃ID) |
| | | */ |
| | | private void triggerScanRequest(DeviceConfig deviceConfig, EnhancedS7Serializer serializer, String glassId) { |
| | | private void triggerScanRequest(DeviceConfig deviceConfig, PlcClient plcClient, String glassId) { |
| | | Map<String, Object> writeFields = new HashMap<>(); |
| | | writeFields.put("plcRequest", 1); |
| | | |
| | |
| | | writeFields.put("plcGlassId", glassId); |
| | | } |
| | | |
| | | plcDynamicDataService.writePlcData(deviceConfig, writeFields, serializer); |
| | | plcClient.writeData(writeFields); |
| | | } |
| | | |
| | | /** |
| | | * 清空PLC请求字段:只清除plcRequest和plcGlassId(不清除MES写区字段) |
| | | */ |
| | | private void clearPlcRequestFields(DeviceConfig deviceConfig, EnhancedS7Serializer serializer) { |
| | | private void clearPlcRequestFields(DeviceConfig deviceConfig, PlcClient plcClient) { |
| | | try { |
| | | Map<String, Object> clearFields = new HashMap<>(); |
| | | clearFields.put("plcRequest", 0); |
| | | clearFields.put("plcGlassId", ""); |
| | | plcDynamicDataService.writePlcData(deviceConfig, clearFields, serializer); |
| | | plcClient.writeData(clearFields); |
| | | } catch (Exception e) { |
| | | log.error("清空PLC请求字段失败: deviceId={}", deviceConfig.getId(), e); |
| | | // 不清空不影响主流程,只记录错误 |
| | |
| | | } |
| | | |
| | | private Map<String, Object> waitForMesData(DeviceConfig deviceConfig, |
| | | EnhancedS7Serializer serializer, |
| | | PlcClient plcClient, |
| | | WorkstationLogicConfig config) throws InterruptedException { |
| | | long timeoutMs = Math.max(config.getScanIntervalMs(), 3_000); |
| | | long deadline = System.currentTimeMillis() + timeoutMs; |
| | | int pollInterval = Math.max(200, Math.min(config.getScanIntervalMs() / 5, 1_000)); |
| | | |
| | | while (System.currentTimeMillis() < deadline) { |
| | | Map<String, Object> mesData = plcDynamicDataService.readPlcData(deviceConfig, MES_FIELDS, serializer); |
| | | Map<String, Object> mesData = plcClient.readData(MES_FIELDS.toArray(new String[0])); |
| | | |
| | | if (mesData != null && !mesData.isEmpty()) { |
| | | Integer mesSend = parseInteger(mesData.get("mesSend")); |
| | |
| | | |
| | | // 超时前最后一次尝试读取 |
| | | log.warn("等待MES数据超时: deviceId={}, timeout={}ms", deviceConfig.getId(), timeoutMs); |
| | | Map<String, Object> lastMesData = plcDynamicDataService.readPlcData(deviceConfig, MES_FIELDS, serializer); |
| | | Map<String, Object> lastMesData = plcClient.readData(MES_FIELDS.toArray(new String[0])); |
| | | if (lastMesData != null && !lastMesData.isEmpty()) { |
| | | log.warn("超时前最后一次读取到的数据: deviceId={}, mesData={}", |
| | | deviceConfig.getId(), lastMesData); |