package com.zy.core.network.real; import HslCommunication.Core.Types.OperateResult; import HslCommunication.Core.Types.OperateResultExOne; import HslCommunication.Profinet.Siemens.SiemensPLCS; import HslCommunication.Profinet.Siemens.SiemensS7Net; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.core.common.DateUtils; import com.core.common.SpringUtils; import com.zy.asrs.entity.BasDevp; import com.zy.asrs.entity.DeviceConfig; import com.zy.asrs.service.BasDevpService; import com.zy.common.utils.RedisUtil; import com.zy.core.News; import com.zy.core.cache.OutputQueue; import com.zy.core.model.CommandResponse; import com.zy.core.model.StationObjModel; import com.zy.core.model.command.StationCommand; import com.zy.core.model.protocol.StationTaskBufferItem; import com.zy.core.network.api.ZyStationConnectApi; import com.zy.core.network.entity.ZyStationStatusEntity; import lombok.extern.slf4j.Slf4j; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; /** * 输送站真实连接(PLC) */ @Slf4j public class ZyStationV4RealConnect implements ZyStationConnectApi { private static final int TASK_AREA_LENGTH = 48; private static final int TASK_AREA_SLOT_SIZE = 12; private static final int TASK_AREA_SLOT_COUNT = 3; private List statusList; private List barcodeOriginList; private SiemensS7Net siemensNet; private DeviceConfig deviceConfig; private RedisUtil redisUtil; public ZyStationV4RealConnect(DeviceConfig deviceConfig, RedisUtil redisUtil) { this.deviceConfig = deviceConfig; this.redisUtil = redisUtil; } @Override public boolean connect() { boolean connected = false; siemensNet = new SiemensS7Net(SiemensPLCS.S1200, deviceConfig.getIp()); OperateResult connect = siemensNet.ConnectServer(); if (connect.IsSuccess) { connected = true; OutputQueue.DEVP.offer(MessageFormat.format("【{0}】输送站plc连接成功 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort())); News.info("输送站plc连接成功 ===>> [id:{}] [ip:{}] [port:{}]", deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort()); } else { OutputQueue.DEVP.offer(MessageFormat.format("【{0}】输送站plc连接失败!!! ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort())); News.error("输送站plc连接失败!!! ===>> [id:{}] [ip:{}] [port:{}]", deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort()); } // siemensNet.ConnectClose(); return connected; } @Override public boolean disconnect() { siemensNet.ConnectClose(); return true; } @Override public List getStatus(Integer deviceNo) { if (statusList == null) { BasDevpService basDevpService = SpringUtils.getBean(BasDevpService.class); if (basDevpService == null) { return Collections.emptyList(); } BasDevp basDevp = basDevpService .getOne(new QueryWrapper().eq("devp_no", deviceConfig.getDeviceNo())); if (basDevp == null) { return Collections.emptyList(); } statusList = JSONObject.parseArray(basDevp.getStationList(), ZyStationStatusEntity.class); if (statusList != null) { statusList.sort(Comparator.comparing(ZyStationStatusEntity::getStationId)); } barcodeOriginList = basDevp.getBarcodeStationList$(); } if (siemensNet == null) { return statusList; } OperateResultExOne result = siemensNet.Read("DB100.0", (short) (statusList.size() * 10)); if (result.IsSuccess) { byte[] taskBufferRaw = readTaskBufferRaw(); for (int i = 0; i < statusList.size(); i++) { ZyStationStatusEntity statusEntity = statusList.get(i); // 站点编号 statusEntity.setTaskNo(siemensNet.getByteTransform().TransInt32(result.Content, i * 10)); // 工作号 statusEntity.setTargetStaNo((int) siemensNet.getByteTransform().TransInt16(result.Content, i * 10 + 4)); // 目标站 boolean[] status = siemensNet.getByteTransform().TransBool(result.Content, i * 10 + 6, 1); statusEntity.setAutoing(status[0]); // 自动 statusEntity.setLoading(status[1]); // 有物 statusEntity.setInEnable(status[2]); // 可入 statusEntity.setOutEnable(status[3]);// 可出 statusEntity.setEmptyMk(status[4]); // 空托盘 statusEntity.setFullPlt(status[5]); // 满托盘 boolean[] status2 = siemensNet.getByteTransform().TransBool(result.Content, i * 10 + 7, 1); statusEntity.setEnableIn(status2[1]);//启动入库 statusEntity.setRunBlock(status2[2]);//重新规划路线 Integer palletHeight = null; if (status[7]) { palletHeight = 1;//低 } if (status2[0]) { palletHeight = 2;//中 } if (status[6]) { palletHeight = 3;//高 } statusEntity.setPalletHeight(palletHeight);//高低信号 statusEntity.setError(0);//默认无报警 statusEntity.setTaskWriteIdx((int) siemensNet.getByteTransform().TransInt16(result.Content, i * 10 + 8));//任务可写区 fillTaskBufferStatus(taskBufferRaw, i, statusEntity); } } // 条码扫描器 OperateResultExOne result2 = siemensNet.Read("DB101.16", (short) (barcodeOriginList.size() * 16)); if (result2.IsSuccess) { for (int i = 0; i < barcodeOriginList.size(); i++) { ZyStationStatusEntity barcodeEntity = findStatusEntityByBarcodeIdx(i + 1); if (barcodeEntity == null) { continue; } String barcode = siemensNet.getByteTransform().TransString(result2.Content, i * 16 + 2, 14, "UTF-8"); barcode = barcode.trim(); barcodeEntity.setBarcode(barcode); } } // 称重 OperateResultExOne result3 = siemensNet.Read("DB102.4", (short) (barcodeOriginList.size() * 4)); if (result3.IsSuccess) { for (int i = 0; i < barcodeOriginList.size(); i++) { ZyStationStatusEntity barcodeEntity = findStatusEntityByBarcodeIdx(i + 1); if (barcodeEntity == null) { continue; } double weight = (double) siemensNet.getByteTransform().TransSingle(result3.Content, i * 4); barcodeEntity.setWeight(weight); } } // 报警信息 OperateResultExOne result4 = siemensNet.Read("DB103.2", (short) (barcodeOriginList.size() * 2)); if (result4.IsSuccess) { for (int i = 0; i < barcodeOriginList.size(); i++) { ZyStationStatusEntity barcodeEntity = findStatusEntityByBarcodeIdx(i + 1); if (barcodeEntity == null) { continue; } StringBuilder sb = new StringBuilder(); boolean[] status1 = siemensNet.getByteTransform().TransBool(result4.Content, i * 2, 1); boolean[] status2 = siemensNet.getByteTransform().TransBool(result4.Content, i * 2 + 1, 1); if(status1[0]){ sb.append("左超宽报警;"); } if(status1[1]) { sb.append("右超宽报警;"); } if(status1[2]) { sb.append("前超长报警;"); } if(status1[3]) { sb.append("后超长报警;"); } if(status1[4]) { sb.append("超高报警;"); } if(status1[5]) { sb.append("有货报警,空托入库时检测托盘上有无货物;"); } if(status1[6]) { sb.append("重量异常报警;"); } if(status1[7]) { sb.append("扫码异常;"); } if(sb.length() > 0) { barcodeEntity.setError(1); }else { barcodeEntity.setError(0); } barcodeEntity.setErrorMsg(sb.toString()); } } return statusList; } @Override public CommandResponse sendCommand(Integer deviceNo, StationCommand command) { CommandResponse commandResponse = new CommandResponse(false); if (null == command) { commandResponse.setMessage("命令为空"); return commandResponse; } getStatus(deviceNo); int stationIdx = findIndex(command.getStationId()); if (stationIdx == -1) { commandResponse.setMessage("命令下发失败,未找到站点状态"); return commandResponse; } ZyStationStatusEntity statusEntity = statusList.get(stationIdx); Integer taskWriteIdx = statusEntity == null ? null : statusEntity.getTaskWriteIdx(); if (taskWriteIdx == null || taskWriteIdx <= 0) { commandResponse.setMessage("命令下发失败,当前无可用任务写入区"); return commandResponse; } int useTaskWriteIdx = getTaskWriteIdx(stationIdx, taskWriteIdx); if (useTaskWriteIdx == -1) { commandResponse.setMessage("命令下发超时,无法找到可用下发区域"); return commandResponse; } int taskBaseOffset = stationIdx * TASK_AREA_LENGTH + (useTaskWriteIdx * TASK_AREA_SLOT_SIZE); OperateResult writeTaskNo = siemensNet.Write("DB13." + taskBaseOffset, command.getTaskNo()); if (!writeTaskNo.IsSuccess) { log.error("写入输送线命令失败。站点编号={},站点数据={}", command.getTaskNo(), JSON.toJSON(command)); commandResponse.setResult(false); commandResponse.setMessage("命令下发失败,写入工作号失败"); return commandResponse; } OperateResult writeTarget = siemensNet.Write("DB13." + (taskBaseOffset + 6), command.getTargetStaNo().shortValue()); if (!writeTarget.IsSuccess) { log.error("写入输送线命令失败。站点编号={},站点数据={}", command.getTaskNo(), JSON.toJSON(command)); commandResponse.setResult(false); commandResponse.setMessage("命令下发失败,写入目标设备号失败"); return commandResponse; } log.info("写入输送线命令成功。任务号={},站点数据={}", command.getTaskNo(), JSON.toJSON(command)); commandResponse.setResult(true); return commandResponse; } @Override public synchronized CommandResponse sendOriginCommand(String address, short[] data) { CommandResponse commandResponse = new CommandResponse(false); if (null == data || data.length == 0) { commandResponse.setMessage("数据为空"); return commandResponse; } OperateResult write = siemensNet.Write(address, data); if (write.IsSuccess) { log.info("写入原始命令成功。地址={},数据={}", address, JSON.toJSON(data)); commandResponse.setResult(true); } else { log.error("写入原始命令失败。地址={},数据={}", address, JSON.toJSON(data)); commandResponse.setResult(false); } return commandResponse; } @Override public byte[] readOriginCommand(String address, int length) { OperateResultExOne result = siemensNet.Read(address, (short) length); if (result.IsSuccess) { return result.Content; } return new byte[0]; } private ZyStationStatusEntity findStatusEntityByBarcodeIdx(Integer barcodeIdx) { Integer stationId = null; for (StationObjModel stationObjModel : barcodeOriginList) { if (stationObjModel.getBarcodeIdx().equals(barcodeIdx)) { stationId = stationObjModel.getStationId(); break; } } for (ZyStationStatusEntity zyStationStatusEntity : statusList) { if(zyStationStatusEntity.getStationId().equals(stationId)) { return zyStationStatusEntity; } } return null; } private int getTaskWriteIdx(int stationIdx, Integer taskWriteIdx) { int useIdx = -1; if (stationIdx < 0 || taskWriteIdx == null || taskWriteIdx <= 0) { return useIdx; } OperateResultExOne resultTask = siemensNet.Read("DB13." + (stationIdx * TASK_AREA_LENGTH), (short) TASK_AREA_LENGTH); if (resultTask.IsSuccess) { int taskNo = siemensNet.getByteTransform().TransInt32(resultTask.Content, taskWriteIdx * TASK_AREA_SLOT_SIZE); int targetPoint = siemensNet.getByteTransform().TransInt16(resultTask.Content, taskWriteIdx * TASK_AREA_SLOT_SIZE + 6); if (taskNo == 0 && targetPoint == 0) { useIdx = taskWriteIdx; } } return useIdx; } private byte[] readTaskBufferRaw() { int totalLength = statusList == null ? 0 : statusList.size() * TASK_AREA_LENGTH; if (totalLength <= 0) { return null; } OperateResultExOne resultTask = siemensNet.Read("DB13.0", (short) totalLength); if (!resultTask.IsSuccess || resultTask.Content == null || resultTask.Content.length < totalLength) { return null; } return resultTask.Content; } private void fillTaskBufferStatus(byte[] taskBufferRaw, int stationIdx, ZyStationStatusEntity statusEntity) { if (statusEntity == null || stationIdx < 0 || taskBufferRaw == null) { statusEntity.setTaskBufferItems(new ArrayList<>()); return; } List itemList = new ArrayList<>(); int stationOffset = stationIdx * TASK_AREA_LENGTH; if (stationOffset + TASK_AREA_LENGTH > taskBufferRaw.length) { statusEntity.setTaskBufferItems(itemList); return; } for (int slotIdx = 1; slotIdx <= TASK_AREA_SLOT_COUNT; slotIdx++) { int offset = stationOffset + (slotIdx * TASK_AREA_SLOT_SIZE); int taskNo = siemensNet.getByteTransform().TransInt32(taskBufferRaw, offset); int targetPoint = siemensNet.getByteTransform().TransInt16(taskBufferRaw, offset + 6); StationTaskBufferItem item = new StationTaskBufferItem(); item.setSlotIdx(slotIdx); item.setTaskNo(taskNo); item.setTargetStaNo(targetPoint); itemList.add(item); } statusEntity.setTaskBufferItems(itemList); } private int findIndex(Integer stationId) { for (int i = 0; i < statusList.size(); i++) { ZyStationStatusEntity statusEntity = statusList.get(i); if (statusEntity.getStationId().equals(stationId)) { return i; } } return -1; } }