1
ZY
2025-03-20 1e86acc5e9fa9b18a6dc43c0ab9c6469723b2395
src/main/java/com/zy/core/thread/SteThread.java
@@ -5,6 +5,7 @@
import HslCommunication.Profinet.Siemens.SiemensPLCS;
import HslCommunication.Profinet.Siemens.SiemensS7Net;
import com.alibaba.fastjson.JSON;
import com.core.common.Cools;
import com.core.common.DateUtils;
import com.core.common.SpringUtils;
import com.core.exception.CoolException;
@@ -12,12 +13,12 @@
import com.zy.asrs.entity.BasSteOpt;
import com.zy.asrs.service.BasSteOptService;
import com.zy.asrs.service.BasSteService;
import com.zy.common.utils.News;
import com.zy.core.ThreadHandler;
import com.zy.core.cache.MessageQueue;
import com.zy.core.cache.OutputQueue;
import com.zy.core.enums.SlaveType;
import com.zy.core.enums.SteStatusType;
import com.zy.core.enums.SteTaskModeType;
import com.zy.core.model.SteSlave;
import com.zy.core.model.Task;
import com.zy.core.model.command.SteCommand;
@@ -27,7 +28,6 @@
import java.text.MessageFormat;
import java.util.Date;
import java.util.Random;
/**
 * shuttle 穿梭车线程
@@ -43,10 +43,8 @@
    private SteProtocol steProtocol;
    private short heartBeatVal = 1;
    private boolean resetFlag = false;
    private int value = 0;
    private Integer lastRow;
    private Integer lastBay;
    private Integer lastLev;
    public SteThread(SteSlave slave) {
        this.slave = slave;
@@ -71,6 +69,8 @@
                    // 写入数据
                    case 2:
                        write((SteCommand) task.getData());
//                        Thread.sleep(200);
//                        readStatus();
                        break;
                    default:
                        break;
@@ -93,9 +93,9 @@
            steProtocol = new SteProtocol();
        }
        steProtocol.setSteNo(slave.getId().shortValue());
        steProtocol.setMode((short) 0);
        steProtocol.setMode((short) -1);
        steProtocol.setStatus(SteStatusType.OFF_LINE);
        steProtocol.setTaskNo(0);
        steProtocol.setTaskNo((short) 0);
        steProtocol.setExecute(false);
        steProtocol.setWaiting(false);
    }
@@ -108,13 +108,13 @@
//        siemensS7Net.setRack(slave.getRack().byteValue());
//        siemensS7Net.setSlot(slave.getSlot().byteValue());
        OperateResult connect = siemensS7Net.ConnectServer();
        if(connect.IsSuccess){
        if (connect.IsSuccess) {
            result = true;
            OutputQueue.CRN.offer(MessageFormat.format( "【{0}】穿梭车plc连接成功 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            log.info("穿梭车plc连接成功 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
            OutputQueue.STE.offer(MessageFormat.format("【{0}】穿梭车plc连接成功 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            News.info("穿梭车plc连接成功 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
        } else {
            OutputQueue.CRN.offer(MessageFormat.format("【{0}】穿梭车plc连接失败!!! ===>> [id:{1}] [ip:{2}] [port:{3}] ", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            log.error("穿梭车plc连接失败!!! ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
            OutputQueue.STE.offer(MessageFormat.format("【{0}】穿梭车plc连接失败!!! ===>> [id:{1}] [ip:{2}] [port:{3}] ", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            News.error("穿梭车plc连接失败!!! ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
            initSte();
        }
//        melsecMcNet.ConnectClose();
@@ -124,15 +124,30 @@
    /**
     * 读取状态
     */
    private void readStatus(){
    private synchronized void readStatus() {
        try {
            OperateResultExOne<byte[]> result = siemensS7Net.Read("V800", (short) 70);
            if (result.IsSuccess) {
                if (null == steProtocol) {
                    steProtocol = new SteProtocol();
                    steProtocol.setSteNo(slave.getId().shortValue());
                }
                steProtocol.setSteNo(siemensS7Net.getByteTransform().TransInt16(result.Content, 0));
                steProtocol.setMode(siemensS7Net.getByteTransform().TransInt16(result.Content, 2));
//                steProtocol.setSteNo(siemensS7Net.getByteTransform().TransInt16(result.Content, 0));
                short i = siemensS7Net.getByteTransform().TransInt16(result.Content, 2);
                if (i == 0) {
                    value++;
                } else {
                    value = 0;
                }
                if (value > 20) {
                    steProtocol.setMode((short) 0);
                } else {
                    if (steProtocol.getMode() != null) {
                        steProtocol.setMode(steProtocol.getMode());
                    } else {
                        steProtocol.setMode((short) 1);
                    }
                }
                steProtocol.setStatus(siemensS7Net.getByteTransform().TransInt16(result.Content, 4));
                OperateResultExOne<Boolean> executeRes = siemensS7Net.ReadBool("V2001.0");
                if (executeRes.IsSuccess) {
@@ -142,9 +157,17 @@
                if (waitingRes.IsSuccess) {
                    steProtocol.setWaiting(waitingRes.Content);
                }
                steProtocol.setAlarm(siemensS7Net.getByteTransform().TransInt32(result.Content, 6));
                steProtocol.setAlarm0(siemensS7Net.getByteTransform().TransInt32(result.Content, 8));
                steProtocol.setCharge(siemensS7Net.getByteTransform().TransInt16(result.Content, 10));
                OperateResultExOne<Boolean> inEmptyRes = siemensS7Net.ReadBool("V2001.2");
                if (inEmptyRes.IsSuccess) {
                    steProtocol.setInEmpty(inEmptyRes.Content);
                }
                OperateResultExOne<Boolean> outEmptyRes = siemensS7Net.ReadBool("V2001.3");
                if (outEmptyRes.IsSuccess) {
                    steProtocol.setOutEmpty(outEmptyRes.Content);
                }
                steProtocol.setAlarm(siemensS7Net.getByteTransform().TransInt16(result.Content, 6));
                steProtocol.setAlarm0(siemensS7Net.getByteTransform().TransInt16(result.Content, 8));
                steProtocol.setCharge(siemensS7Net.getByteTransform().TransSingle(result.Content, 10));
//                steProtocol.setFullCharge();
//                steProtocol.setLowCharge();
                steProtocol.setFeed(siemensS7Net.getByteTransform().TransInt16(result.Content, 14));
@@ -154,7 +177,7 @@
                steProtocol.setPos(siemensS7Net.getByteTransform().TransInt16(result.Content, 18));
                steProtocol.setLoad(siemensS7Net.getByteTransform().TransInt16(result.Content, 20));
                steProtocol.setTrack(siemensS7Net.getByteTransform().TransInt16(result.Content, 22));
                steProtocol.setTaskNo(siemensS7Net.getByteTransform().TransInt32(result.Content, 24));
                steProtocol.setTaskNo(siemensS7Net.getByteTransform().TransInt16(result.Content, 24));
                steProtocol.setTaskType(siemensS7Net.getByteTransform().TransInt16(result.Content, 28));
                steProtocol.setRow(siemensS7Net.getByteTransform().TransInt16(result.Content, 30));
                steProtocol.setBay(siemensS7Net.getByteTransform().TransInt16(result.Content, 32));
@@ -170,16 +193,21 @@
                steProtocol.setCrnStopRun(siemensS7Net.getByteTransform().TransInt16(result.Content, 38));
                steProtocol.setCrnStopFork(siemensS7Net.getByteTransform().TransInt16(result.Content, 40));
                steProtocol.setCrnAllowRun(siemensS7Net.getByteTransform().TransInt16(result.Content, 42));
                steProtocol.setChargeStatus(siemensS7Net.getByteTransform().TransInt16(result.Content, 44));
                OutputQueue.CRN.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), slave.getId()));
                OutputQueue.STE.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功", DateUtils.convert(new Date()), slave.getId()));
                // 复位信号
                if (steProtocol.getWaiting()) {
                    News.info("-------------第一步、[穿梭车号:{}, 工作号:{}]==>> 状态为{},等待WCS确认!!{}",
                            slave.getId(), steProtocol.getTaskNo(), steProtocol.getStatus(), resetFlag);
                    if (resetFlag) {
                        SteCommand steCommand = new SteCommand();
                        steCommand.setComplete(true);
                        if (write(steCommand) && confirmPos()) {
                            resetFlag = false;
                            News.info("第二步、发送复位命令成功 resetFlag = false,[穿梭车号:{}, 工作号:{}]==>> 状态为{},等待WCS确认!!{}",
                                    slave.getId(), steProtocol.getTaskNo(), steProtocol.getStatus(), resetFlag);
                        }
                    }
                }
@@ -188,21 +216,27 @@
                // 根据实时信息更新数据库
                BasSteService service = SpringUtils.getBean(BasSteService.class);
                if (null != service) {
                    // 同步pakMk
                    BasSte one = service.selectById(slave.getId());
                    if (one != null) {
                        steProtocol.setPakMk(one.getPakMk());
                    }
                    BasSte basSte = new BasSte();
                    basSte.setSteNo(slave.getId());
                    if (!service.updateById(steProtocol.toSqlModel(basSte))){
                        log.error("穿梭车plc数据库更新失败 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
                    if (!service.updateById(steProtocol.toSqlModel(basSte))) {
                        News.error("穿梭车plc数据库更新失败 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
                    }
                }
            } else {
                OutputQueue.CRN.offer(MessageFormat.format("【{0}】{1}穿梭车plc状态信息失败",DateUtils.convert(new Date()), slave.getId()));
                throw new CoolException(MessageFormat.format( "穿梭车plc状态信息失败 ===>> [id:{0}] [ip:{1}] [port:{2}]", slave.getId(), slave.getIp(), slave.getPort()));
                OutputQueue.STE.offer(MessageFormat.format("【{0}】{1}穿梭车plc状态信息失败", DateUtils.convert(new Date()), slave.getId()));
                throw new CoolException(MessageFormat.format("穿梭车plc状态信息失败 ===>> [id:{0}] [ip:{1}] [port:{2}]", slave.getId(), slave.getIp(), slave.getPort()));
            }
        } catch (Exception e) {
            e.printStackTrace();
            OutputQueue.CRN.offer(MessageFormat.format("【{0}】读取穿梭车plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            log.error("读取穿梭车plc状态信息失败 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
//            e.printStackTrace();
            OutputQueue.STE.offer(MessageFormat.format("【{0}】读取穿梭车plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
//            News.error("读取穿梭车plc状态信息失败 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
            initSte();
        }
@@ -211,47 +245,61 @@
    /**
     * 写入数据
     */
    private boolean write(SteCommand command){
    private synchronized boolean write(SteCommand command) {
        if (null == command) {
            log.error("穿梭车写入命令为空");
            News.error("穿梭车写入命令为空");
            return false;
        }
        command.setSteNo(slave.getId());
        OperateResult result = null;
        // 开始任务
        if (!command.getComplete()) {
            //组织任务前,先清空写任务确认位,以及任务完成确认位
            OperateResult result01 = siemensS7Net.Write("V2000.0", false);
            OperateResult result02 = siemensS7Net.Write("V2000.1", false);
            // 1.任务号
            OperateResult result0 = siemensS7Net.Write("V998", command.getTaskNo().shortValue());
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 作业
            if (command.getTaskMode() != 0) {
                // 1.任务号
                OperateResult result0 = siemensS7Net.Write("V1000", command.getTaskNo());
                // 2.作业
                OperateResult result1 = siemensS7Net.Write("V1000", command.getTaskMode());     // todo
                OperateResult result1 = siemensS7Net.Write("V1000", command.getTaskMode());
                // 3.确认开始任务
                if (result0.IsSuccess && result1.IsSuccess) {
                    result = siemensS7Net.Write("V2000.0", true);
                }
            // 其他指令
                // 其他指令
            } else {
                // 控制模式
                if (command.getControlMode() != null) {
                    result =  siemensS7Net.Write("V1010", command.getControlMode());
                // 复位信号
                    result = siemensS7Net.Write("V1010", command.getControlMode());
                    // 复位信号
                } else if (command.getReset() != null) {
                    result =  siemensS7Net.Write("V2000.2", command.getReset());
                // 删除指令
                    result = siemensS7Net.Write("V2000.2", command.getReset());
                    // 删除指令
                } else if (command.getDelete() != null) {
                    result =  siemensS7Net.Write("V2000.3", command.getDelete());
                // 无效指令
                    result = siemensS7Net.Write("V2000.3", command.getDelete());
                    // 无效指令
                } else if (command.getRun() != null) {
                    result = siemensS7Net.Write("V1016", command.getRun());
                    // 无效指令
                } else {
                    return false;
                }
            }
        // 任务完成
            // 任务完成
        } else {
            result = siemensS7Net.Write("D0", true);
            News.info("收到穿梭板确认信号后准备给复位标记,穿梭板ID={}, 任务号={}, 穿梭板状态={}", slave.getId(), steProtocol.getTaskNo(), steProtocol.getStatus());
            siemensS7Net.Write("V998", (short) 0);
            siemensS7Net.Write("V1000", (short) 0);
            siemensS7Net.Write("V2000.0", false);
            result = siemensS7Net.Write("V2000.1", true);
        }
        try {
@@ -281,59 +329,87 @@
                }
            }
        } catch (Exception ignore) {}
        } catch (Exception ignore) {
        }
        if (result != null && result.IsSuccess) {
            // 维护数据库排列层
            if (!steProtocol.getWaiting()) {
                this.lastRow = command.getRow().intValue();
                this.lastBay = command.getBay().intValue();
                this.lastLev = command.getLev().intValue();
                if (!Cools.isEmpty(command.getRow(), command.getBay(), command.getLev())) {
                    this.modifyPos(command.getRow().intValue(), command.getBay().intValue(), command.getLev().intValue());
                }
            }
            log.info("穿梭车命令下发[id:{}] >>>>> {}", slave.getId(), JSON.toJSON(command));
            OutputQueue.CRN.offer(MessageFormat.format("【{0}】[id:{1}] >>>>> 命令下发: {2}", DateUtils.convert(new Date()), slave.getId(), JSON.toJSON(command)));
            News.info("穿梭车命令下发[id:{}] >>>>> {}", slave.getId(), JSON.toJSON(command));
            OutputQueue.STE.offer(MessageFormat.format("【{0}】[id:{1}] >>>>> 命令下发: {2}", DateUtils.convert(new Date()), slave.getId(), JSON.toJSON(command)));
            try {
                Thread.sleep(500);
            } catch (Exception e) {
            }
            OperateResultExOne<byte[]> result1 = siemensS7Net.Read("V998", (short) 4);
            if (result1.IsSuccess) {
                short taskNo = siemensS7Net.getByteTransform().TransInt16(result1.Content, 0);
                short taskType = siemensS7Net.getByteTransform().TransInt16(result1.Content, 2);
//                readStatus();
                News.info("穿梭板任务下发成功后休眠200ms立即回读写入数据,穿梭板ID={}, 任务号={}, 作业类型={}", slave.getId(), taskNo, taskType);
                News.info("穿梭板任务下发成功后休眠200ms立即回读穿梭板状态,穿梭板ID={}, 任务号={}, 穿梭板状态={}", slave.getId(), steProtocol.getTaskNo(), steProtocol.getStatus());
            }
            resetFlag = false;
            return true;
        } else {
            OutputQueue.CRN.offer(MessageFormat.format("【{0}】写入穿梭车plc数据失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            log.error("写入穿梭车plc数据失败 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
            OutputQueue.STE.offer(MessageFormat.format("【{0}】写入穿梭车plc数据失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            News.error("写入穿梭车plc数据失败 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
            //写入失败后,重新添加commanddao 任务队列中,并立即回读一次设备状态
//            MessageQueue.offer(SlaveType.Ste, slave.getId(), new Task(2, command));
//            readStatus();
            initSte();
            return false;
        }
    }
    public void modifyPos(Integer row, Integer bay, Integer lev) {
        this.lastRow = row;
        this.lastBay = bay;
        this.lastLev = lev;
        BasSteService service = SpringUtils.getBean(BasSteService.class);
        if (!service.updatePos(this.slave.getId(), row, bay, lev)) {
            News.error("更新{}号穿梭车定位失败 ===>> 排:【{}】, 列:【{}】,层:【{}】", this.slave.getId(), row, bay, lev);
        }
    }
    public boolean confirmPos() {
        if (this.lastRow != null && this.lastRow != 0) {
            if (this.lastBay != null && this.lastBay != 0) {
                if (this.lastLev != null && this.lastLev != 0) {
                    BasSteService service = SpringUtils.getBean(BasSteService.class);
                    BasSte basSte = service.selectById(slave.getId());
                    if (basSte != null) {
                        // 更新plc数据块
                        short[] arr = new short[] {this.lastRow.shortValue(), this.lastBay.shortValue(), this.lastLev.shortValue()};
                        OperateResult result = siemensS7Net.Write("V1002", arr);
                        if (result.IsSuccess) {
                            // 更新数据库
                            if (service.updatePos(this.lastRow, this.lastBay, this.lastLev) > 0) {
                                this.lastRow = null;
                                this.lastBay = null;
                                this.lastLev = null;
                                return true;
                            } else {
                                log.error("{}号穿梭车修改数据库定位失败!!!", slave.getId());
                            }
                        }
                    }
        BasSteService service = SpringUtils.getBean(BasSteService.class);
        BasSte basSte = service.selectById(slave.getId());
        if (basSte != null) {
            // 更新plc数据块
            short[] arr = new short[]{basSte.getRow().shortValue(), basSte.getBay().shortValue(), basSte.getLev().shortValue()};
            OperateResult result = siemensS7Net.Write("V1002", arr);
            if (result.IsSuccess) {
                // 更新数据库
                if (service.updatePakMk(this.slave.getId(), "N")) {
                    return true;
                } else {
                    News.error("{}号穿梭车修改数据库定位失败!!!", slave.getId());
                }
            }
        }
        return false;
    }
    public boolean modifyPosHandle(Integer row, Integer bay, Integer lev) {
        short[] arr = new short[]{row.shortValue(), bay.shortValue(), lev.shortValue()};
        OperateResult result = siemensS7Net.Write("V1002", arr);
        if (!result.IsSuccess) {
            News.error("更新{}号穿梭车定位失败 ===>> 排:【{}】, 列:【{}】,层:【{}】", this.slave.getId(), row, bay, lev);
            return false;
        }
        BasSteService service = SpringUtils.getBean(BasSteService.class);
        if (!service.updatePos(this.slave.getId(), row, bay, lev)) {
            News.error("更新{}号穿梭车定位失败 ===>> 排:【{}】, 列:【{}】,层:【{}】", this.slave.getId(), row, bay, lev);
            return false;
        }
        return true;
    }
    @Override
@@ -344,7 +420,7 @@
    /**
     * 心跳
     */
    private void heartbeat(){
    private void heartbeat() {
        if (heartBeatVal == 1) {
            heartBeatVal = 2;
        } else {
@@ -352,10 +428,16 @@
        }
        OperateResult write = siemensS7Net.Write("D10", heartBeatVal);
        if (!write.IsSuccess) {
            log.error("输送线plc编号={} 心跳失败", slave.getId());
            News.error("输送线plc编号={} 心跳失败", slave.getId());
        }
    }
//    public void modifyPos(int wrkNo, int row, int bay, int lev) {
//        BasSteService service = SpringUtils.getBean(BasSteService.class);
//        if (!service.updatePos(wrkNo,this.slave.getId(), row, bay, lev)) {
//            News.error("更新{}号穿梭车定位失败 ===>> 排:【{}】, 列:【{}】,层:【{}】", this.slave.getId(), row, bay, lev);
//        }
//    }
    /******************************************************************************************/
    /**************************************** 测试专用 *****************************************/
@@ -363,19 +445,21 @@
    public static void main(String[] args) throws InterruptedException {
        SteSlave slave = new SteSlave();
        slave.setId(1);
        slave.setIp("192.168.3.39");
        slave.setPort(5015);
        slave.setIp("192.168.2.1");
        slave.setPort(502);
        SteThread thread = new SteThread(slave);
        thread.connect();
        thread.readStatus();
        System.out.println(JSON.toJSONString(thread.steProtocol));
        // 任务作业
        SteCommand command = new SteCommand();
        command.setSteNo(1); // 堆垛机编号
        command.setTaskNo(new Random().nextInt(9000)); // 工作号
        command.setTaskMode(SteTaskModeType.IN_LEFT); // 任务模式
        thread.write(command);
//        SteCommand command = new SteCommand();
//        command.setSteNo(1); // 堆垛机编号
//        Random random = new Random();
//        int taskNo = random.nextInt(9090);
//        command.setTaskNo(taskNo); // 工作号
//        command.setTaskMode(SteTaskModeType.MOVE_LEFT); // 任务模式
//        thread.write(command);
        // 任务完成
//        SteCommand command = new SteCommand();
@@ -390,14 +474,19 @@
        // 复位信号
//        SteCommand command = new SteCommand();
//        command.setReset((short) 1);
//        command.setReset(Boolean.TRUE);
//        thread.write(command);
        // 删除指令
//        SteCommand command = new SteCommand();
//        command.setDelete((short) 1);
//        command.setDelete(Boolean.TRUE);
//        thread.write(command);
        // 穿梭车运行禁止
        SteCommand command = new SteCommand();
        command.setRun((short) 0);
        thread.write(command);
    }
}