zhangc
2025-04-11 b2e9d1f13a8a88e2963f504926234589fa2d2787
src/main/java/com/zy/core/thread/LiftThread.java
@@ -1,422 +1,67 @@
package com.zy.core.thread;
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.core.common.DateUtils;
import com.core.common.SpringUtils;
import com.core.exception.CoolException;
import com.zy.asrs.entity.BasLift;
import com.zy.asrs.entity.BasLiftOpt;
import com.zy.asrs.mapper.WrkMastMapper;
import com.zy.asrs.service.BasLiftOptService;
import com.zy.asrs.service.BasLiftService;
import com.zy.common.utils.RedisUtil;
import com.zy.core.News;
import com.zy.common.ExecuteSupport;
import com.zy.common.model.NavigateNode;
import com.zy.core.ThreadHandler;
import com.zy.core.cache.MessageQueue;
import com.zy.core.cache.OutputQueue;
import com.zy.core.enums.*;
import com.zy.core.model.LiftSlave;
import com.zy.core.model.Task;
import com.zy.core.model.command.*;
import com.zy.core.model.protocol.LiftStaProtocol;
import com.zy.core.enums.ForkLiftTaskModeType;
import com.zy.core.enums.LiftCommandModeType;
import com.zy.core.enums.LiftProtocolStatusType;
import com.zy.core.model.CommandResponse;
import com.zy.core.model.command.LiftCommand;
import com.zy.core.model.protocol.LiftProtocol;
import com.zy.core.model.protocol.StaProtocol;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import com.zy.core.model.protocol.LiftStaProtocol;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * 提升机线程
 */
@Data
@Slf4j
public class LiftThread implements  Runnable, ThreadHandler {
public interface LiftThread extends ThreadHandler {
    private SiemensS7Net siemensS7Net;
    private LiftSlave slave;
    private LiftProtocol liftProtocol;
    private RedisUtil redisUtil;
    private List<LiftStaProtocol> liftStaProtocols = new ArrayList<>();
    LiftProtocol getStatus();//获取提升机状态
    public LiftThread(LiftSlave slave,RedisUtil redisUtil) {
        this.slave = slave;
        this.redisUtil = redisUtil;
    LiftProtocol getStatus(boolean clone);//获取提升机状态
        //初始化站点
        for (LiftSlave.Sta sta : this.slave.getSta()) {
            LiftStaProtocol liftStaProtocol = new LiftStaProtocol();
            liftStaProtocol.setStaNo(sta.getStaNo());//站点号
            liftStaProtocol.setLev(sta.getLev());//站点楼层
            liftStaProtocols.add(liftStaProtocol);
        }
    List<LiftStaProtocol> getLiftStaProtocols();
    }
    CommandResponse move(LiftCommand command);//升降移动
    @Override
    public void run() {
        this.connect();
        while (true) {
            try {
                int step = 1;
                Task task = MessageQueue.poll(SlaveType.Lift, slave.getId());
                if (task != null) {
                    step = task.getStep();
                }
                switch (step) {
                    // 读数据
                    case 1:
                        read();
                        break;
                    // 写入数据
                    case 2:
                        write((NyLiftCommand) task.getData());
                        break;
                    //分配任务
                    case 3:
                        assignWork((LiftAssignCommand) task.getData());
                        break;
                    default:
                        break;
                }
                Thread.sleep(500);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    CommandResponse palletInOut(LiftCommand command);//托盘出入
    @Override
    public boolean connect() {
        boolean result = false;
        //-------------------------提升机连接方法------------------------//
        siemensS7Net = new SiemensS7Net(SiemensPLCS.S1200, slave.getIp());
        OperateResult connect = siemensS7Net.ConnectServer();
        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());
        } 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());
        }
        siemensS7Net.ConnectClose();
        //-------------------------提升机连接方法------------------------//
        return result;
    }
    CommandResponse lock(LiftCommand command);//锁定提升机
    @Override
    public void close() {
        siemensS7Net.ConnectClose();
    }
    CommandResponse unlock(LiftCommand command);//解锁提升机
    private void read() {
        try {
            readStatus();
    CommandResponse reset(LiftCommand command);//复位
            //提升机处于运行状态,将标记置为true
            if (liftProtocol.getBusy()) {
                liftProtocol.setPakMk(true);
            }
    boolean isIdle();//是否空闲
            //提升机处于未运行、就绪、标记true、有任务号
            if (!liftProtocol.getBusy()
                    && liftProtocol.getPakMk()
                    && liftProtocol.getTaskNo() != 0) {
                //还有未完成的命令
                executeWork(liftProtocol.getTaskNo());
            }
        } catch (Exception e) {
            OutputQueue.LIFT.offer(MessageFormat.format("【{0}】提升机plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
        }
    }
    boolean isDeviceIdle();//设备是否空闲
    private void readStatus() {
        try {
            //获取提升机数据
            OperateResultExOne<byte[]> result1 = siemensS7Net.Read("DB4.0", (short) 10);
            if (result1.IsSuccess) {
                if (null == liftProtocol) {
                    liftProtocol = new LiftProtocol();
                    liftProtocol.setLiftNo(slave.getId().shortValue());
                }
                //读取4.0-4.7数据
                boolean[] status1 = siemensS7Net.getByteTransform().TransBool(result1.Content, 0, 1);
                //读取5.0-5.7数据
                boolean[] status2 = siemensS7Net.getByteTransform().TransBool(result1.Content, 1, 1);
                //模式
                liftProtocol.setModel(status1[0]);
                //忙闲
                liftProtocol.setBusy(status1[1]);
                //前超限
                liftProtocol.setFrontOverrun(status1[4]);
                //后超限
                liftProtocol.setBackOverrun(status1[5]);
                //左超限
                liftProtocol.setLeftOverrun(status1[6]);
                //右超限
                liftProtocol.setRightOverrun(status1[7]);
                //超高
                liftProtocol.setOverHeight(status2[0]);
                //超重
                liftProtocol.setOverWeight(status2[1]);
                //有托盘
                liftProtocol.setHasTray(status2[5]);
                //有小车
                liftProtocol.setHasCar(status2[6]);
                //设备故障
                liftProtocol.setDeviceError(status2[7]);
                //任务号
                liftProtocol.setTaskNo(siemensS7Net.getByteTransform().TransInt16(result1.Content, 2));
                //目的地址
                liftProtocol.setDistAddress(siemensS7Net.getByteTransform().TransInt16(result1.Content, 4));
                //已完成任务号
                liftProtocol.setCompleteTaskNo(siemensS7Net.getByteTransform().TransInt16(result1.Content, 6));
                //当前楼层
                liftProtocol.setLev(siemensS7Net.getByteTransform().TransInt16(result1.Content, 8));
    boolean isDeviceIdle(ExecuteSupport support);//设备是否空闲
                //将提升机状态保存至数据库
                BasLiftService liftService = SpringUtils.getBean(BasLiftService.class);
                BasLift basLift = liftService.selectById(liftProtocol.getLiftNo());
                if (basLift == null) {
                    basLift = new BasLift();
                    //提升机号
                    basLift.setLiftNo(slave.getId());
                    liftService.insert(basLift);
                }
                basLift.setStatus(liftProtocol.getProtocolStatus());
                basLift.setWrkNo(liftProtocol.getTaskNo().intValue());
                basLift.setUpdateTime(new Date());
                basLift.setPakMk(liftProtocol.getPakMk());
                basLift.setModel(liftProtocol.getModel());
                basLift.setBusy(liftProtocol.getBusy());
                basLift.setFrontOverrun(liftProtocol.getFrontOverrun());
                basLift.setBackOverrun(liftProtocol.getBackOverrun());
                basLift.setLeftOverrun(liftProtocol.getLeftOverrun());
                basLift.setRightOverrun(liftProtocol.getRightOverrun());
                basLift.setOverHeight(liftProtocol.getOverHeight());
                basLift.setOverWeight(liftProtocol.getOverWeight());
                basLift.setHasTray(liftProtocol.getHasTray());
                basLift.setHasCar(liftProtocol.getHasCar());
                basLift.setDeviceError(liftProtocol.getDeviceError());
                basLift.setDistAddress(liftProtocol.getDistAddress().intValue());
                basLift.setCompleteTaskNo(liftProtocol.getCompleteTaskNo().intValue());
                basLift.setLev(liftProtocol.getLev().intValue());
                if (liftService.updateById(basLift)) {
                    OutputQueue.LIFT.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), slave.getId()));
//                    log.info(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), slave.getId()));
                }
            }else {
                OutputQueue.LIFT.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()));
            }
            Thread.sleep(200);
    boolean setProtocolStatus(LiftProtocolStatusType status);//设置工作状态
            //获取提升机站点数据
            OperateResultExOne<byte[]> result2 = siemensS7Net.Read("DB14.0", (short) (10 * liftStaProtocols.size()));
            if (result1.IsSuccess) {
                for (int i = 0; i < slave.getSta().size(); i++) {
                    LiftStaProtocol liftStaProtocol = liftStaProtocols.get(i);
                    int i1 = 0 + (i * 10);
                    int i2 = 1 + (i * 10);
                    //读取x4.0-x4.7数据
                    boolean[] status1 = siemensS7Net.getByteTransform().TransBool(result2.Content, i1, 1);
                    //读取x5.0-x5.7数据
                    boolean[] status2 = siemensS7Net.getByteTransform().TransBool(result2.Content, i2, 1);
                    //模式
                    liftStaProtocol.setModel(status1[0]);
                    //忙闲
                    liftStaProtocol.setBusy(status1[1]);
                    //有托盘
                    liftStaProtocol.setHasTray(status1[2]);
                    //前超限
                    liftStaProtocol.setFrontOverrun(status1[4]);
                    //后超限
                    liftStaProtocol.setBackOverrun(status1[5]);
                    //左超限
                    liftStaProtocol.setLeftOverrun(status1[6]);
                    //右超限
                    liftStaProtocol.setRightOverrun(status1[7]);
                    //超高
                    liftStaProtocol.setOverHeight(status2[0]);
                    //超重
                    liftStaProtocol.setOverWeight(status2[1]);
                    //有小车
                    liftStaProtocol.setHasCar(status2[6]);
                    //设备故障
                    liftStaProtocol.setDeviceError(status2[7]);
                    //任务号
                    liftStaProtocol.setTaskNo(siemensS7Net.getByteTransform().TransInt16(result2.Content, 2));
                    //已完成任务号
                    liftStaProtocol.setCompleteTaskNo(siemensS7Net.getByteTransform().TransInt16(result2.Content, 6));
                }
            }
    boolean setSyncTaskNo(Integer taskNo);//设置工作号
        } catch (Exception e) {
            OutputQueue.LIFT.offer(MessageFormat.format("【{0}】提升机plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
        }
    }
    boolean isLock(ExecuteSupport support);
    private boolean write(NyLiftCommand command){
        if (null == command) {
            News.error("提升机写入命令为空");
            return false;
        }
    int generateDeviceTaskNo(int taskNo, ForkLiftTaskModeType type);//生成硬件设备工作号
        command.setLiftNo(slave.getId().shortValue());
        short[] array = getCommandArr(command);//获取命令报文
    String getLiftLocNo(int lev);//获取提升机位置
        OperateResult result = siemensS7Net.Write("41088", array);
        if (result != null && result.IsSuccess) {
            News.info("提升机命令下发[id:{}] >>>>> {}", slave.getId(), JSON.toJSON(command));
            OutputQueue.LIFT.offer(MessageFormat.format("【{0}】[id:{1}] >>>>> 命令下发: {2}", DateUtils.convert(new Date()), slave.getId(), JSON.toJSON(command)));
            return true;
        } else {
            OutputQueue.LIFT.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());
            return false;
        }
    }
    String getLiftStandByLocNo(int lev, boolean in);//获取提升机待机位
    //获取命令报文
    private short[] getCommandArr(NyLiftCommand command) {
        // 开始任务
        short[] array = new short[4];
        if (command.getTaskModel() != null) {
            //任务类型
            array[0] = command.getTaskModel();
        }
        if (command.getSourceSta() != null) {
            //源站台编号
            array[1] = command.getSourceSta();
        }
        if (command.getTargetSta() != null) {
            //目标站台编号
            array[2] = command.getTargetSta();
        }
        if (command.getTaskNo() != null) {
            //任务号
            array[3] = command.getTaskNo();
        }
        return array;
    }
    List<NavigateNode> getLiftStaNodes(int lev);
    //分配任务
    private void assignWork(LiftAssignCommand assignCommand) {
        LiftRedisCommand redisCommand = new LiftRedisCommand();
        redisCommand.setLiftNo(assignCommand.getLiftNo());//提升机号
        redisCommand.setWrkNo(assignCommand.getTaskNo());//工作号
        redisCommand.setCommandStep(0);//命令执行步序
        redisCommand.setAssignCommand(assignCommand);//命令
        //任务数据保存到redis
        redisUtil.set("lift_wrk_no_" + assignCommand.getTaskNo(), JSON.toJSONString(redisCommand));
        liftProtocol.setAssignCommand(assignCommand);
        liftProtocol.setProtocolStatus(LiftProtocolStatusType.WORKING);
        //执行下发任务
        executeWork(assignCommand.getTaskNo());
    }
    //***************获取命令*****************
    List<LiftCommand> getMoveCommand(Integer taskNo, Integer sourceLev, Integer targetLev, LiftCommandModeType mode);//提升机移动
    //执行任务
    private boolean executeWork(Short wrkNo) {
        //读取redis数据
        if (wrkNo == null) {
            return false;
        }
    List<LiftCommand> getMoveWithShuttleCommand(Integer taskNo, Integer sourceLev, Integer targetLev, LiftCommandModeType mode);//载车移动
        WrkMastMapper wrkMastMapper = SpringUtils.getBean(WrkMastMapper.class);
        Object o = redisUtil.get("lift_wrk_no_" + wrkNo);
        if (o == null) {
            return false;
        }
        LiftRedisCommand redisCommand = JSON.parseObject(o.toString(), LiftRedisCommand.class);
        List<NyLiftCommand> commands = redisCommand.getAssignCommand().getCommands();
        //当前步序
        int commandStep = redisCommand.getCommandStep();
        //总步序
        int size = commands.size();
    List<LiftCommand> getPalletInCommand(Integer taskNo, Integer sourceLev, Integer targetLev);//托盘入
        //取出命令
        NyLiftCommand command = commands.get(commandStep);
    List<LiftCommand> getPalletOutCommand(Integer taskNo, Integer sourceLev, Integer targetLev);//托盘出
        //下发命令
        if (!write(command)) {
            News.error("提升机命令下发失败,提升机号={},任务数据={}", command.getLiftNo(), JSON.toJSON(command));
            return false;
        }
    List<LiftCommand> getLockCommand(Integer taskNo, Boolean lock);//锁定/解锁提升机
        News.info("提升机命令下发成功,提升机号={},任务数据={}", command.getLiftNo(), JSON.toJSON(command));
        //将标记置为false(防止重发)
        liftProtocol.setPakMk(false);
        //保存数据到数据库做流水
        BasLiftOptService liftOptService = SpringUtils.getBean(BasLiftOptService.class);
        if (liftOptService != null) {
            short[] commandArr = getCommandArr(command);//获取命令报文
            BasLiftOpt opt = new BasLiftOpt(
                    redisCommand.getWrkNo().intValue(),
                    redisCommand.getLiftNo().intValue(),
                    new Date(),
                    null,
                    null,
                    null,
                    JSON.toJSONString(command),
                    JSON.toJSONString(commandArr),
                    JSON.toJSONString(liftProtocol)
            );
            liftOptService.insert(opt);
        }
        //判断数据是否执行完成
        if (commandStep < size - 1) {
            //更新redis数据
            //步序增加
            commandStep++;
            redisCommand.setCommandStep(commandStep);
            //任务数据保存到redis
            redisUtil.set("lift_wrk_no_" + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand));
        }else {
            //已执行完成
            //删除redis
            redisUtil.del("lift_wrk_no_" + redisCommand.getWrkNo());
            //对主线程抛出等待确认状态waiting
            liftProtocol.setProtocolStatus(LiftProtocolStatusType.WAITING);
            News.info("提升机任务执行下发完成等待执行结束,提升机号={},任务数据={}", command.getLiftNo(), JSON.toJSON(command));
        }
        return true;
    }
    /******************************************************************************************/
    /**************************************** 测试专用 *****************************************/
    /*****************************************************************************************/
    public static void main(String[] args) throws InterruptedException {
        LiftSlave slave = new LiftSlave();
        slave.setId(1);
        slave.setIp("192.168.4.24");
        slave.setPort(502);
//        LiftThread thread = new LiftThread(slave,);
//        thread.connect();
//        thread.readStatus();
//
//        LiftCommand command = new LiftCommand();
//        command.setRun((short) 1);
//        command.setDistPosition((short) 12);
//        command.setSpeed((short) 300);
//        command.setHeight2((short) 100);
//        command.setHeight3((short) 200);
//        command.setHeight4((short) 303);
//        command.setLiftLock(true);
//        thread.write(command);
    }
    List<LiftCommand> getShuttleSignalCommand(Integer taskNo, Boolean signal);//小车已到位/已驶离信号
}