package com.dy.rtuMw.server.upgrade; import com.alibaba.fastjson2.annotation.JSONField; import com.dy.common.softUpgrade.parse.HexFileParse; import com.dy.common.softUpgrade.state.UpgradeRtu; import com.dy.common.softUpgrade.state.UpgradeState; import com.dy.common.softUpgrade.state.UpgradeTaskVo; import com.dy.common.util.Callback; import com.dy.common.util.DateTime; import lombok.Data; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; /** * @Author: liurunyu * @Date: 2024/11/4 14:52 * @Description */ @Data public class UpgradeTask { private static final Logger log = LogManager.getLogger(UpgradeTask.class.getName()); protected static final String TaskOverType_Natural = "自然" ; protected static final String TaskOverType_Force = "强制" ; @JSONField(serialize = false) protected Integer failTryTimes ;//升级失败后,重新偿试升级次数,0表示不重新偿试升级 @JSONField(serialize = false) protected Integer ugMaxRtuSameTime ;//同时升级RTU最大个数 public String setupDt ;//设置时间(yyyy-mm-dd HH:MM:SS) @JSONField(serialize = false) private Long setupDtLong ;//设置时间 public UpgradeTaskVo taskVo ;//升级任务值对象 @JSONField(serialize = false) protected byte[][] softFileDataGrp ;//以512字节为单位把升级程序数据分组 @JSONField(serialize = false) protected ConcurrentHashMap upgradeRtus;//升级状态 public boolean taskIsOver = false ;//任务是否完成 public String taskOverType = "" ;//任务完成方式(自然,强制) public String taskOverDt = "" ;//任务完成时间(yyyy-mm-dd HH:MM:SS) /////////////////////////////////////////////////// //以下内部控制用 @JSONField(serialize = false) private int curUgRunningRtuTotal = 0 ;//当前正在升级的RTU个数 public UpgradeTask() { this.curUgRunningRtuTotal = 0 ; } /** * 初始化配置信息 */ public void initOption(Integer failTryTimes, Integer ugMaxRtuSameTime) { this.failTryTimes = failTryTimes; this.ugMaxRtuSameTime = ugMaxRtuSameTime; } /** * 设置升级任务 * @param taskVo UpgradeTaskVo 升级任务对象 * @throws Exception */ public void setTask(UpgradeTaskVo taskVo) throws Exception { if(taskVo.id == null || taskVo.id.trim().length() == 0){ throw new Exception("升级任务id必须提供") ; } if(taskVo.softFileName == null || taskVo.softFileName.trim().length() == 0){ throw new Exception("升级软件(hex)文件名称必须提供") ; } if(taskVo.softStoreAddr == null || taskVo.softStoreAddr.trim().length() != 8){ throw new Exception("升级程序存放地址不合法,必须是8字符(十六进制)的字符串") ; } if(taskVo.softStartAddr == null || taskVo.softStartAddr.trim().length() != 8){ throw new Exception("程序覆盖起始地址不合法,必须是8字符(十六进制)的字符串") ; } if(taskVo.softFileData64 == null || taskVo.softFileData64.trim().length() == 0){ throw new Exception("升级程序内容必须提供") ; } if(taskVo.softBytesCalculate == null){ throw new Exception("公式计算升级程序有效序字节数必须提供") ; } if(taskVo.softByteSrc16 == null){ throw new Exception("有效升级程序字节数CRC16校验值必须提供") ; } if(taskVo.rtuAddrList == null || taskVo.rtuAddrList.size() <= 0){ throw new Exception("升级设备RTU地址必须提供") ; } if(taskVo.callbackWebUrl == null || taskVo.callbackWebUrl.trim().equals("")){ throw new Exception("回调网址必须提供") ; } this.setupDt = DateTime.yyyy_MM_dd_HH_mm_ss() ; this.setupDtLong = System.currentTimeMillis() ; this.taskVo = taskVo ; this.upgradeRtus = new ConcurrentHashMap<>(); if(taskVo.softFileData64 != null && !taskVo.softFileData64.trim().equals("")){ taskVo.softFileData = Base64.getDecoder().decode(taskVo.softFileData64); List listBytes = new HexFileParse().splitBytesByUnit512(taskVo.softFileData); this.softFileDataGrp = listBytes.toArray(new byte[0][]); try{ for(String rtuAddr : this.taskVo.rtuAddrList){ //此时状态设置成离线状态 UpgradeRtuDev ugRtu = new UpgradeRtuDev(this.taskVo, this.failTryTimes, rtuAddr, this.softFileDataGrp.length, UpgradeRtuDev.STATE_OFFLINE) ; this.upgradeRtus.put(rtuAddr, ugRtu) ; } }catch (Exception e){ log.error(e); } } } /** * RTU有上行数据了,触发下发升级数据 * @param rtuAddr * @param code * @param callbackCom */ public void trigger(String rtuAddr, String code, String protocolName, Short protocolVersion, Callback callbackCom){ if(this.upgradeRtus != null && this.upgradeRtus.size() > 0 && this.taskVo.rtuAddrList != null && this.taskVo.rtuAddrList.size() > 0){ UpgradeRtu ugRtu = this.upgradeRtus.get(rtuAddr) ; if(ugRtu == null){ //根据方法setTask的逻辑,只要RTU在升级之列,此处ugRtuState一定不为null //为保险,实现下面逻辑 if(taskVo.rtuAddrList.contains(rtuAddr)){ ugRtu = new UpgradeRtuDev(this.taskVo, this.failTryTimes, rtuAddr, this.taskVo.softFileData.length) ; upgradeRtus.put(rtuAddr, ugRtu) ; }else{ //rtu不在升级之列 return ; } } if(ugRtu != null){ if(ugRtu.isOver){ //当前RTU已经升级完成,无需再升级 return; }else{ if(UpgradeUnit.confVo.ugMaxRtuAtOnce > 0){ //设置了同时升级的RTU最大数量的限制 if(ugRtu.state == UpgradeRtuDev.STATE_OFFLINE){ //初始态,说明升级任务设置以来,该RTU第一次上行数据 if(this.curUgRunningRtuTotal <= UpgradeUnit.confVo.ugMaxRtuAtOnce){ //当前正在升级的RTU数量还未受限 ugRtu.trigger(code, protocolName, protocolVersion, this.softFileDataGrp, callbackCom) ; }else{ //同时升级的RTU数量受限,等待下次机会 //但先表明一下状态 ugRtu.state = UpgradeRtuDev.STATE_UNSTART ; return ; } }else if(ugRtu.state == UpgradeRtuDev.STATE_UNSTART){ //根据上面逻辑, 说明必然在线了 if(this.curUgRunningRtuTotal <= UpgradeUnit.confVo.ugMaxRtuAtOnce){ //当前正在升级的RTU数量还未受限 ugRtu.trigger(code, protocolName, protocolVersion, this.softFileDataGrp, callbackCom) ; }else{ //同时升级的RTU数量受限,等待下次机会 return ; } }else{ //RTU已经处于升级过程中 ugRtu.trigger(code, protocolName, protocolVersion, this.softFileDataGrp, callbackCom) ; } }else{ //没有设置同时升级的RTU最大数量的限制 ugRtu.trigger(code, protocolName, protocolVersion, this.softFileDataGrp, callbackCom) ; } } }else{ //rtu不在升级之列 return ; } } } /** * 强制结束升级任务 */ public void forceOver(){ if(!this.taskIsOver){ this.taskIsOver = true ;//强制设置任务完成 this.taskOverType = TaskOverType_Force ;//任务完成方式(自然,强制) this.taskOverDt = DateTime.yyyy_MM_dd_HH_mm_ss() ;//任务完成时间(yyyy-mm-dd HH:MM:SS) //this.taskVo.rtuAddrList.clear(); //this.upgradeState.clear(); } } /** * 当前升级状态 * @return */ public UpgradeState currentUpgradeState() { UpgradeState state = new UpgradeState() ; if(this.taskVo.rtuAddrList != null && this.taskVo.rtuAddrList.size() > 0){ state.rtuTotal = this.taskVo.rtuAddrList.size() ; if(this.upgradeRtus != null && this.upgradeRtus.size() > 0){ AtomicBoolean hasRunning = new AtomicBoolean(false); this.upgradeRtus.values().stream().forEach(info ->{ if(info.state == UpgradeRtu.STATE_OFFLINE){ state.offLineTotal ++ ; }else if(info.state == UpgradeRtu.STATE_UNSTART){ state.unStartTotal ++ ; }else if(info.state == UpgradeRtu.STATE_RUNNING){ state.runningTotal ++ ; }else if(info.state == UpgradeRtu.STATE_SUCCESS) { state.successTotal++; }else if(info.state == UpgradeRtu.STATE_FAIL) { state.failTotal++; }else if(info.state == UpgradeRtu.STATE_FAILONE) { state.failOneTotal++; state.failTotal++; }else if(info.state == UpgradeRtu.STATE_FAILOFFLINE) { state.failTotal++; state.failOffTotal++; } if(info.isOver){ state.overTotal++; }else{ hasRunning.set(true); } }); if(!hasRunning.get()){ state.allOver = true ; }else{ state.allOver = false ; } } } return state ; } /** * Rtu升级信息 * @param rtuAddr * @return */ public UpgradeRtu upgradeInfos(String rtuAddr){ return this.upgradeRtus.get(rtuAddr) ; } /** * 一些Rtu升级信息 * @param rtuAddrList * @return */ public List upgradeInfos(List rtuAddrList){ List list = new ArrayList<>() ; for(String rtuAddr : rtuAddrList){ UpgradeRtu info = this.upgradeRtus.get(rtuAddr) ; if(info != null){ list.add(info) ; } } return list ; } /** * 全部Rtu升级信息 * @return */ public List upgradeInfoAll(){ if(this.upgradeRtus != null && this.upgradeRtus.size() > 0){ return this.upgradeRtus.values().stream().toList(); }else{ return null ; } } /////////////////////////////////////////////////////////// //以下方法为内部服务,不对外提供服务 /////////////////////////////////////////////////////////// /** * 判断是否没用任何一个RTU进行过升级,而且超过了时限 * @return -1:无一RTU升级且超时,0:无RTU升级但未超时等待,1有RTU升级正常执行 */ protected int countNoOneRtuUpgradeInDuration(){ if(this.upgradeRtus == null || upgradeRtus.size() == 0){ //当前没有任何一个设备进行过升级 Long now = System.currentTimeMillis() ; if(now - this.setupDtLong > UpgradeUnit.confVo.noOneRtuUpgradeMaxDuration){ return -1 ; } }else{ Collection col = this.upgradeRtus.values() ; for(UpgradeRtu info : col){ if(info.currentPackage > 0){ //当前有设备进行过升级 return 1 ; } } Long now = System.currentTimeMillis() ; if(now - this.setupDtLong > UpgradeUnit.confVo.noOneRtuUpgradeMaxDuration){ return -1 ; } } return 0 ; } /** * 统计当前正在升级的RTU数量,为同时升级数量限制做准备 */ protected void countRunningRtuCount(){ int runningTotal = 0 ; Collection col = this.upgradeRtus.values() ; for(UpgradeRtu info : col){ if(info.state == UpgradeRtu.STATE_RUNNING){ runningTotal ++ ; } } this.curUgRunningRtuTotal = runningTotal ; } /** * 统计需要升级但当前离线RTU的情况,超过时限的设备为升级完成 */ protected void countOffRtuAndSetIfOver() { Long now = System.currentTimeMillis() ; if(now - this.setupDtLong > UpgradeUnit.confVo.rtuOffLineWaitDuration){ //rtu离线,等待其升级的时长(毫秒),超过配置的最大时长,设置其升级失败,且设置升级任务完成 if (this.taskVo.rtuAddrList != null && this.taskVo.rtuAddrList.size() > 0) { Collection col = this.upgradeRtus.values() ; for(UpgradeRtu info : col){ if(info.state == UpgradeRtu.STATE_OFFLINE){ info.isOver = true ; info.state = UpgradeRtu.STATE_FAILOFFLINE ; } } } } } /** * 统计是否升级全部结束 */ protected boolean countIsAllOver() { if (this.taskVo.rtuAddrList != null && this.taskVo.rtuAddrList.size() > 0) { Collection col = this.upgradeRtus.values() ; for(UpgradeRtu info : col){ if(info.isOver == false){ return false ; } } } return true ; } }