|
|
|
@ -8,21 +8,17 @@ import com.platform.info.dto.CommandResultParam;
|
|
|
|
|
import com.platform.info.dto.QueryResultParam;
|
|
|
|
|
import com.platform.info.enums.CommandTypeEnum;
|
|
|
|
|
import com.platform.info.enums.UavTypeEnum;
|
|
|
|
|
import com.platform.service.clientmanage.HaborClient.UavQueryResultParam;
|
|
|
|
|
import com.platform.util.ByteUtils;
|
|
|
|
|
import com.platform.util.JSONUtils;
|
|
|
|
|
import io.netty.buffer.ByteBuf;
|
|
|
|
|
import io.netty.buffer.PooledByteBufAllocator;
|
|
|
|
|
import io.netty.util.Timeout;
|
|
|
|
|
import lombok.Getter;
|
|
|
|
|
import lombok.Setter;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.concurrent.Executors;
|
|
|
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
|
|
|
import java.util.concurrent.ScheduledFuture;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
|
|
|
|
|
/** 记录指令状态,回报指令结果*/
|
|
|
|
@ -36,34 +32,49 @@ public class CommandRecord {
|
|
|
|
|
protected ByteBuf commandBuf = null; // 指令注入内容
|
|
|
|
|
protected String commandUniId; // 中心指控指令唯一码
|
|
|
|
|
|
|
|
|
|
@Getter@Setter
|
|
|
|
|
private UavQueryResultParam uavQueryResultParam;
|
|
|
|
|
|
|
|
|
|
// 指令状态
|
|
|
|
|
@Getter
|
|
|
|
|
private AtomicInteger receiveFrameCount = new AtomicInteger(0); // 接收到的指令帧数, 150帧还未判断成功则判定为失败
|
|
|
|
|
// private long startTime = 0 ; // 接收到的指令帧数, 150帧还未判断成功则判定为失败
|
|
|
|
|
private final int MAX_RECEIVE_COUNT = 150; // 接收到的指令帧数, 150帧还未判断成功则判定为失败
|
|
|
|
|
private final long TIMEOUT_THRESHOLD = 30*1000; // 从下发超过5s未回报,则判定为失败
|
|
|
|
|
private static final long DEFAULT_TIMEOUT_THRESHOLD = 10*1000; // 默认超时时间, 从下发超过5s未回报,则判定为失败
|
|
|
|
|
|
|
|
|
|
@Getter@Setter
|
|
|
|
|
protected int status;
|
|
|
|
|
public static final int FAILED = -1; // 指令失败
|
|
|
|
|
public static final int NO_COMMAND = 0; // 空闲
|
|
|
|
|
public static final int WAITING_RESULT = 2; // 等待回报
|
|
|
|
|
public static final int WAITING_RESULT = 1; // 等待回报
|
|
|
|
|
|
|
|
|
|
// 定时任务管理
|
|
|
|
|
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(50); // 单线程池管理超时任务
|
|
|
|
|
ScheduledFuture<?> timeoutFuture = null; // 超时任务
|
|
|
|
|
@Getter @Setter
|
|
|
|
|
private Timeout timeout;
|
|
|
|
|
@Getter
|
|
|
|
|
long expireMills; // 超时时间 ms
|
|
|
|
|
// private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(50); // 单线程池管理超时任务
|
|
|
|
|
// ScheduledFuture<?> timeoutFuture = null; // 超时任务
|
|
|
|
|
// todo 过期时间控制
|
|
|
|
|
public CommandRecord(CommandTypeEnum commandType, HaborClient client) {
|
|
|
|
|
this(commandType, client, 16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CommandRecord(CommandTypeEnum commandType, HaborClient client, int contentSize) {
|
|
|
|
|
public CommandRecord(CommandTypeEnum commandType, HaborClient client, int commandContentSize) {
|
|
|
|
|
this(commandType, client, 16, DEFAULT_TIMEOUT_THRESHOLD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CommandRecord(CommandTypeEnum commandType, HaborClient client, int commandContentSize, long expireMills) {
|
|
|
|
|
this.commandType = commandType;
|
|
|
|
|
this.client = client;
|
|
|
|
|
this.commandBuf = PooledByteBufAllocator.DEFAULT.buffer(contentSize);
|
|
|
|
|
this.commandBuf = PooledByteBufAllocator.DEFAULT.buffer(commandContentSize);
|
|
|
|
|
this.status = NO_COMMAND;
|
|
|
|
|
this.expireMills = expireMills;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String shortInfo() {
|
|
|
|
|
return String.format("{commandType=%s, uniIsd=%s, code=%s}", commandType.getInfo(), commandUniId, ByteUtils.byteToHex(code));
|
|
|
|
|
}
|
|
|
|
|
/** 记录指令信息,启动定时判断任务*/
|
|
|
|
|
public void recordCommand(byte commandCode, String uniId, ByteBuf commandSlice) {
|
|
|
|
|
this.code = commandCode;
|
|
|
|
|
this.commandBuf.clear();
|
|
|
|
@ -72,41 +83,49 @@ public class CommandRecord {
|
|
|
|
|
this.status = WAITING_RESULT;
|
|
|
|
|
this.receiveFrameCount.set(0);
|
|
|
|
|
|
|
|
|
|
//启动一个超时检查的定时任务
|
|
|
|
|
this.timeoutFuture = scheduleTimeoutCheck();
|
|
|
|
|
|
|
|
|
|
// 启动延时任务
|
|
|
|
|
CommandManager commandManager = CommandManager.getInstance();
|
|
|
|
|
commandManager.addCommandRecord(this);
|
|
|
|
|
// this.timeoutFuture = scheduleTimeoutCheck();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 定时任务:每5秒检查一次所有命令是否超时
|
|
|
|
|
private ScheduledFuture<?> scheduleTimeoutCheck() {
|
|
|
|
|
log.debug("[cac] {} {}指令超时判断定时任务启动", client.shortInfo(), commandType.getInfo());
|
|
|
|
|
// 每5秒检查一次所有命令记录的超时状态
|
|
|
|
|
return scheduler.schedule(() -> {
|
|
|
|
|
if (status != NO_COMMAND ) {
|
|
|
|
|
status = FAILED; // 标记超时为失败
|
|
|
|
|
log.error("[cac] {} {}指令超时", client.shortInfo(), commandType.getInfo());
|
|
|
|
|
switch (commandType) {
|
|
|
|
|
case CONTROL:
|
|
|
|
|
this.notifyControlCommandResult(client.uavId, false);
|
|
|
|
|
break;
|
|
|
|
|
case PARAM_BIND:
|
|
|
|
|
this.notifyParamBindCommandResult(client.uavId, client.uavType, false);
|
|
|
|
|
break;
|
|
|
|
|
case ROUTE_BIND:
|
|
|
|
|
this.notifyParamBindCommandResult(client.uavId, client.uavType, false);
|
|
|
|
|
break;
|
|
|
|
|
case PARAM_QUERY:
|
|
|
|
|
this.notifyParamQueryCommandResult(client.uavId, client.uavType, false, null);
|
|
|
|
|
}
|
|
|
|
|
client.switchToCommonData(); // todo 需要优化,尽量不要在里面用client的控制逻辑
|
|
|
|
|
}
|
|
|
|
|
}, TIMEOUT_THRESHOLD, TimeUnit.MILLISECONDS); // 设置延迟时间
|
|
|
|
|
}
|
|
|
|
|
// // 定时任务:每5秒检查一次所有命令是否超时
|
|
|
|
|
// private ScheduledFuture<?> scheduleTimeoutCheck() {
|
|
|
|
|
// log.debug("[cac] {} {}指令超时判断定时任务启动", client.shortInfo(), commandType.getInfo());
|
|
|
|
|
// // 每5秒检查一次所有命令记录的超时状态
|
|
|
|
|
// return scheduler.schedule(() -> {
|
|
|
|
|
// if (status != NO_COMMAND ) {
|
|
|
|
|
// status = FAILED; // 标记超时为失败
|
|
|
|
|
// log.error("[cac] {} {}指令超时", client.shortInfo(), commandType.getInfo());
|
|
|
|
|
// switch (commandType) {
|
|
|
|
|
// case CONTROL:
|
|
|
|
|
// this.notifyControlCommandResult(client.uavId, false);
|
|
|
|
|
// break;
|
|
|
|
|
// case PARAM_BIND:
|
|
|
|
|
// this.notifyParamBindCommandResult(client.uavId, client.uavType, false);
|
|
|
|
|
// break;
|
|
|
|
|
// case ROUTE_BIND:
|
|
|
|
|
// this.notifyParamBindCommandResult(client.uavId, client.uavType, false);
|
|
|
|
|
// break;
|
|
|
|
|
// case PARAM_QUERY:
|
|
|
|
|
// this.notifyParamQueryCommandResult(client.uavId, client.uavType, false);
|
|
|
|
|
// }
|
|
|
|
|
// client.switchToCommonData(); // todo 需要优化,尽量不要在里面用client的控制逻辑
|
|
|
|
|
// }
|
|
|
|
|
// }, DEFAULT_TIMEOUT_THRESHOLD, TimeUnit.MILLISECONDS); // 设置延迟时间
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
public void cancelScheduleTimeout() {
|
|
|
|
|
if (this.timeoutFuture != null && !this.timeoutFuture.isCancelled()) {
|
|
|
|
|
if (this.timeoutFuture.cancel(true)) {
|
|
|
|
|
log.debug("[cac] {} 取消{}指令超时判断定时任务", client.shortInfo(), commandType.getInfo());
|
|
|
|
|
// if (this.timeoutFuture != null && !this.timeoutFuture.isCancelled()) {
|
|
|
|
|
// if (this.timeoutFuture.cancel(true)) {
|
|
|
|
|
// log.debug("[cac] {} 取消{}指令超时判断定时任务", client.shortInfo(), commandType.getInfo());
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
if (timeout!= null && !timeout.isCancelled()) {
|
|
|
|
|
if (timeout.cancel()){
|
|
|
|
|
log.debug("[cac] {} 取消{}指令超时判断任务: {}", client.shortInfo(), commandType.getInfo(), shortInfo());
|
|
|
|
|
} else {
|
|
|
|
|
log.warn("[cac] {} 无法取消{}指令的超时判断任务:{},任务可能已在执行中", client.shortInfo(), commandType.getInfo(), shortInfo());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -152,7 +171,7 @@ public class CommandRecord {
|
|
|
|
|
bindResultParam.setCommandSource(1);
|
|
|
|
|
bindResultParam.setUavType(uavType.getRemoteCode());
|
|
|
|
|
bindResultParam.setUavParamBindCode(ByteUtils.byteToInt(code));
|
|
|
|
|
bindResultParam.setBindResult(isSuccess?0:1);
|
|
|
|
|
bindResultParam.setBindResult(isSuccess);
|
|
|
|
|
boolean notifySuccess = CacHpApi.uavParamBindResultNotify(bindResultParam);
|
|
|
|
|
log.info("[cac] {} 参数装订{}结果 发送{}", client.shortInfo(), isSuccess?"成功":"失败", notifySuccess?"成功":"失败");
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
@ -160,7 +179,7 @@ public class CommandRecord {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void notifyParamQueryCommandResult(String uavId, UavTypeEnum uavType, boolean isSuccess, HaborClient.UavQueryResultParam uavQueryResultParam) {
|
|
|
|
|
public void notifyParamQueryCommandResult(String uavId, UavTypeEnum uavType, boolean isSuccess) {
|
|
|
|
|
QueryResultParam queryResultParam = new QueryResultParam();
|
|
|
|
|
try {
|
|
|
|
|
queryResultParam.setGcsId(GlobalData.GCS_ID);
|
|
|
|
@ -169,8 +188,8 @@ public class CommandRecord {
|
|
|
|
|
queryResultParam.setCommandSource(1);
|
|
|
|
|
queryResultParam.setUavType(uavType.getRemoteCode());
|
|
|
|
|
queryResultParam.setUavParamQueryCode(ByteUtils.byteToInt(code));
|
|
|
|
|
queryResultParam.setQueryResult(isSuccess?0:1);
|
|
|
|
|
if (isSuccess) {
|
|
|
|
|
queryResultParam.setQueryResult(isSuccess);
|
|
|
|
|
if (isSuccess && uavQueryResultParam != null) {
|
|
|
|
|
String queryResultContent = uavQueryResultParam.toJsonStr();
|
|
|
|
|
queryResultParam.setQueryResultContent(queryResultContent);
|
|
|
|
|
}
|
|
|
|
|