package com.mes.service.impl; import com.alibaba.fastjson.JSONObject; import com.github.xingshuangs.iot.common.enums.EDataType; import com.github.xingshuangs.iot.protocol.s7.serializer.S7Parameter; import com.mes.entity.PlcAddress; import com.mes.s7.enhanced.EnhancedS7Serializer; import com.mes.service.PlcDynamicDataService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * PLC动态数据读写服务实现 * 通过PlcAddress中的addressMapping配置动态读写任意字段组合 * * @author huang * @date 2025/11/05 */ @Slf4j @Service public class PlcDynamicDataServiceImpl implements PlcDynamicDataService { /** * 根据PlcAddress配置和字段名称读取PLC数据 * * @param config PLC地址映射配置 * @param fieldNames 要读取的字段名称列表 * @param s7Serializer S7序列化器 * @return 字段名->值 的Map */ @Override public Map readPlcData(PlcAddress config, List fieldNames, EnhancedS7Serializer s7Serializer) { if (config == null || config.getAddressMapping() == null) { throw new IllegalArgumentException("PlcAddress配置或addressMapping不能为空"); } try { // 解析addressMapping JSON配置 JSONObject addressMapping = JSONObject.parseObject(config.getAddressMapping()); // 构建S7Parameter列表 List parameters = buildS7Parameters(config, addressMapping, fieldNames); // 从PLC读取数据 List results = s7Serializer.read(parameters); // 将结果转换为Map Map resultMap = new HashMap<>(); for (int i = 0; i < fieldNames.size() && i < results.size(); i++) { String fieldName = fieldNames.get(i); Object value = results.get(i).getValue(); resultMap.put(fieldName, value); } return resultMap; } catch (Exception e) { log.error("读取PLC数据失败,请检查:1.PLC IP地址是否正确[{}] 2.PLC设备是否在线 3.网络连接是否正常,module: {}, 详细错误: {}", config.getPlcIp(), config.getModule(), e.getMessage(), e); return new HashMap<>(); } } /** * 根据PlcAddress配置和数据Map写入PLC * * @param config PLC地址映射配置 * @param dataMap 字段名->值 的Map * @param s7Serializer S7序列化器 */ @Override public void writePlcData(PlcAddress config, Map dataMap, EnhancedS7Serializer s7Serializer) { if (config == null || config.getAddressMapping() == null) { throw new IllegalArgumentException("PlcAddress配置或addressMapping不能为空"); } try { // 解析addressMapping JSON配置 JSONObject addressMapping = JSONObject.parseObject(config.getAddressMapping()); // 构建S7Parameter列表,并填充值 List parameters = buildS7ParametersWithValues(config, addressMapping, dataMap); // 写入PLC s7Serializer.write(parameters); } catch (Exception e) { log.error("写入PLC数据失败,请检查:1.PLC IP地址是否正确[{}] 2.PLC设备是否在线 3.网络连接是否正常,module: {}, 详细错误: {}", config.getPlcIp(), config.getModule(), e.getMessage(), e); } } /** * 读取PLC所有字段 * * @param config PLC地址映射配置 * @param s7Serializer S7序列化器 * @return 所有字段的值 */ @Override public Map readAllPlcData(PlcAddress config, EnhancedS7Serializer s7Serializer) { if (config == null || config.getAddressMapping() == null) { throw new IllegalArgumentException("PlcAddress配置或addressMapping不能为空"); } // 获取所有字段名 JSONObject addressMapping = JSONObject.parseObject(config.getAddressMapping()); List allFields = new ArrayList<>(addressMapping.keySet()); // 读取所有字段 return readPlcData(config, allFields, s7Serializer); } /** * 读取单个字段 * * @param config PLC地址映射配置 * @param fieldName 字段名 * @param s7Serializer S7序列化器 * @return 字段值 */ @Override public Object readPlcField(PlcAddress config, String fieldName, EnhancedS7Serializer s7Serializer) { List fields = new ArrayList<>(); fields.add(fieldName); Map result = readPlcData(config, fields, s7Serializer); return result.get(fieldName); } /** * 写入单个字段 * * @param config PLC地址映射配置 * @param fieldName 字段名 * @param value 字段值 * @param s7Serializer S7序列化器 */ @Override public void writePlcField(PlcAddress config, String fieldName, Object value, EnhancedS7Serializer s7Serializer) { Map dataMap = new HashMap<>(); dataMap.put(fieldName, value); writePlcData(config, dataMap, s7Serializer); } /** * 构建S7Parameter列表(不包含值) * * @param config PLC地址配置 * @param addressMapping 地址映射 * @param fieldNames 字段名列表 * @return S7Parameter列表 */ private List buildS7Parameters(PlcAddress config, JSONObject addressMapping, List fieldNames) { List parameters = new ArrayList<>(); for (String fieldName : fieldNames) { if (!addressMapping.containsKey(fieldName)) { log.warn("字段 {} 在addressMapping中不存在,跳过", fieldName); continue; } // 获取字段的偏移地址 int offset = addressMapping.getInteger(fieldName); // 构建完整地址:dbArea + offset(如:DB12.2) String fullAddress = config.getDbArea() + "." + offset; // 创建S7Parameter,默认使用UINT16类型(16位无符号整数) S7Parameter parameter = new S7Parameter(fullAddress, EDataType.UINT16, 1); parameters.add(parameter); } return parameters; } /** * 构建S7Parameter列表(包含值) * * @param config PLC地址配置 * @param addressMapping 地址映射 * @param dataMap 字段名->值 的Map * @return S7Parameter列表 */ private List buildS7ParametersWithValues(PlcAddress config, JSONObject addressMapping, Map dataMap) { List parameters = new ArrayList<>(); for (Map.Entry entry : dataMap.entrySet()) { String fieldName = entry.getKey(); Object value = entry.getValue(); if (!addressMapping.containsKey(fieldName)) { log.warn("字段 {} 在addressMapping中不存在,跳过", fieldName); continue; } // 获取字段的偏移地址 int offset = addressMapping.getInteger(fieldName); // 构建完整地址 String fullAddress = config.getDbArea() + "." + offset; // 创建S7Parameter,设置值 S7Parameter parameter = new S7Parameter(fullAddress, EDataType.UINT16, 1); parameter.setValue(value); parameters.add(parameter); } return parameters; } }