|
|
@ -10,7 +10,8 @@ import io.netty.buffer.ByteBuf;
|
|
|
|
import io.netty.buffer.PooledByteBufAllocator;
|
|
|
|
import io.netty.buffer.PooledByteBufAllocator;
|
|
|
|
import io.netty.buffer.Unpooled;
|
|
|
|
import io.netty.buffer.Unpooled;
|
|
|
|
import io.netty.channel.Channel;
|
|
|
|
import io.netty.channel.Channel;
|
|
|
|
import io.netty.util.concurrent.ScheduledFuture;
|
|
|
|
import io.netty.channel.ChannelFuture;
|
|
|
|
|
|
|
|
import io.netty.util.concurrent.Future;
|
|
|
|
import lombok.Getter;
|
|
|
|
import lombok.Getter;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
|
|
|
|
|
@ -25,8 +26,9 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
* @Date : 2024/9/18 10:38
|
|
|
|
* @Date : 2024/9/18 10:38
|
|
|
|
* @Description : 飞控客户端
|
|
|
|
* @Description : 飞控客户端
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@Slf4j @Getter
|
|
|
|
@Slf4j
|
|
|
|
public class HaborClient extends BaseClient {
|
|
|
|
@Getter
|
|
|
|
|
|
|
|
public abstract class HaborClient extends BaseClient {
|
|
|
|
// static HashSet<String> fkSnSet = new HashSet<>();
|
|
|
|
// static HashSet<String> fkSnSet = new HashSet<>();
|
|
|
|
protected UavTypeEnum uavType;
|
|
|
|
protected UavTypeEnum uavType;
|
|
|
|
protected byte fkId;
|
|
|
|
protected byte fkId;
|
|
|
@ -34,12 +36,15 @@ public class HaborClient extends BaseClient {
|
|
|
|
|
|
|
|
|
|
|
|
// 数据交换控制
|
|
|
|
// 数据交换控制
|
|
|
|
protected final AtomicBoolean needToSendCommonData = new AtomicBoolean(false); // 是否发送常发帧
|
|
|
|
protected final AtomicBoolean needToSendCommonData = new AtomicBoolean(false); // 是否发送常发帧
|
|
|
|
protected int commonDataFreq = 1; // 默认发送频率, 每秒发送帧数, 以各型号子类为准
|
|
|
|
protected int commonDataFreq; // 默认发送频率, 每秒发送帧数, 以各型号子类为准
|
|
|
|
protected ScheduledFuture scheduledFuture;
|
|
|
|
protected volatile int targetPeriod;
|
|
|
|
|
|
|
|
protected Future scheduledFuture;
|
|
|
|
|
|
|
|
protected static final int MIN_SCHEDULE_DELAY = 1; // 最小调度延迟,避免过于频繁的调度
|
|
|
|
|
|
|
|
protected static final int DEFAULT_COMMON_DATA_FREQ = 5; // 默认常发帧发送频率,每秒发送帧数
|
|
|
|
// 数据帧内容
|
|
|
|
// 数据帧内容
|
|
|
|
protected AtomicUByte frameIdx = new AtomicUByte(); // 飞控包序号
|
|
|
|
protected AtomicUByte frameIdx = new AtomicUByte(); // 飞控包序号
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected boolean resourceAllocated;
|
|
|
|
protected DataByteBuf dataBufToSend; // 默认发送常发数据帧 ; // 实际数据发送定时任务发送的数据内容,发送时将引用以下dataBuf
|
|
|
|
protected DataByteBuf dataBufToSend; // 默认发送常发数据帧 ; // 实际数据发送定时任务发送的数据内容,发送时将引用以下dataBuf
|
|
|
|
protected CommonDataBuf commonDataBuf; // 常发数据帧, 复用
|
|
|
|
protected CommonDataBuf commonDataBuf; // 常发数据帧, 复用
|
|
|
|
protected ControlDataBuf controlDataBuf; // 开关指令数据帧, 复用
|
|
|
|
protected ControlDataBuf controlDataBuf; // 开关指令数据帧, 复用
|
|
|
@ -49,7 +54,6 @@ public class HaborClient extends BaseClient {
|
|
|
|
protected static final int FRAME_SIZE = 32; // 如果各型号不一样,该字段取消final,并在子类中初始化
|
|
|
|
protected static final int FRAME_SIZE = 32; // 如果各型号不一样,该字段取消final,并在子类中初始化
|
|
|
|
protected static final byte[] HEAD = new byte[]{(byte) 0xeb, (byte) 0x90};
|
|
|
|
protected static final byte[] HEAD = new byte[]{(byte) 0xeb, (byte) 0x90};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 控制指令回报判断, 指令队列目前只允许一个指令,前一个指令回报或过期后才能发送下一个指令
|
|
|
|
// 控制指令回报判断, 指令队列目前只允许一个指令,前一个指令回报或过期后才能发送下一个指令
|
|
|
|
protected CommandRecord previousControl;
|
|
|
|
protected CommandRecord previousControl;
|
|
|
|
// 装订指令回报判断
|
|
|
|
// 装订指令回报判断
|
|
|
@ -63,41 +67,44 @@ public class HaborClient extends BaseClient {
|
|
|
|
protected ByteBuf telemetryBufHeadToCac;
|
|
|
|
protected ByteBuf telemetryBufHeadToCac;
|
|
|
|
protected int cacHeadLength; // 中心指控协议头长度, 见协议序号1-10
|
|
|
|
protected int cacHeadLength; // 中心指控协议头长度, 见协议序号1-10
|
|
|
|
protected AtomicUShort cacFrameIdx = new AtomicUShort(); // cac包序号
|
|
|
|
protected AtomicUShort cacFrameIdx = new AtomicUShort(); // cac包序号
|
|
|
|
|
|
|
|
protected long lastSendTime = 0;
|
|
|
|
|
|
|
|
|
|
|
|
public HaborClient(String sn, Channel channel) {
|
|
|
|
public HaborClient(String sn, Channel channel) {
|
|
|
|
super(sn, channel);
|
|
|
|
super(sn, channel);
|
|
|
|
// channel绑定客户端
|
|
|
|
// channel绑定客户端
|
|
|
|
channel.attr(ClientManager.CLIENT_ATTRIBUTE_KEY).setIfAbsent(this);
|
|
|
|
channel.attr(ClientManager.CLIENT_ATTRIBUTE_KEY).setIfAbsent(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static HaborClient createClient(UavTypeEnum uavType, String haborSn, Channel channel) {
|
|
|
|
|
|
|
|
switch (uavType) {
|
|
|
|
|
|
|
|
case FP981A:
|
|
|
|
|
|
|
|
return new HaborClient981A(haborSn, channel);
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
public String toString() {
|
|
|
|
return getClass().getSimpleName()+ "{" +
|
|
|
|
return getClass().getSimpleName() + "{" +
|
|
|
|
"channel=" + channel.id() +
|
|
|
|
"channel=" + channel.id() +
|
|
|
|
", sn='" + sn + '\'' +
|
|
|
|
", sn='" + sn + '\'' +
|
|
|
|
", ip='" + ip + '\'' +
|
|
|
|
", ip='" + ip + '\'' +
|
|
|
|
", port='" + port + '\'' +
|
|
|
|
", port='" + port + '\'' +
|
|
|
|
", uavId='" + uavId + '\'' +
|
|
|
|
", uavId='" + uavId + '\'' +
|
|
|
|
", fkId=" + fkId +
|
|
|
|
", fkId=" + fkId +
|
|
|
|
", uavType=" + uavType.getInfo() +
|
|
|
|
", uavType=" + uavType.getInfo() +
|
|
|
|
'}';
|
|
|
|
'}';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public String shortInfo() {
|
|
|
|
public String shortInfo() {
|
|
|
|
return "[sn='" + sn + '\'' +
|
|
|
|
return "[sn='" + sn + '\'' +
|
|
|
|
", uavId='" + uavId + '\'' +
|
|
|
|
", uavId='" + uavId + '\'' +
|
|
|
|
", fkId=" + fkId +
|
|
|
|
", fkId=" + fkId +
|
|
|
|
", uavType=" + uavType.getInfo() +
|
|
|
|
", uavType=" + uavType.getInfo() +
|
|
|
|
']';
|
|
|
|
']';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public static HaborClient createClient(UavTypeEnum uavType, String haborSn, Channel channel) {
|
|
|
|
|
|
|
|
switch (uavType) {
|
|
|
|
|
|
|
|
case FP981A:
|
|
|
|
|
|
|
|
return new HaborClient981A(haborSn, channel);
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@ -120,14 +127,25 @@ public class HaborClient extends BaseClient {
|
|
|
|
return ClientTypeEnum.HABOR;
|
|
|
|
return ClientTypeEnum.HABOR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**被管理时初始化*/
|
|
|
|
/**
|
|
|
|
protected void resourceAllocate() {}
|
|
|
|
* 被管理时初始化
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
protected abstract void resourceAllocate();
|
|
|
|
|
|
|
|
|
|
|
|
/**被移除管理时, 释放相关资源*/
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 被移除管理时, 释放相关资源
|
|
|
|
|
|
|
|
*/
|
|
|
|
protected void resourceRelease() {
|
|
|
|
protected void resourceRelease() {
|
|
|
|
commonDataBuf.release();
|
|
|
|
// FIXME 2025/2/8: 安全释放资源
|
|
|
|
controlDataBuf.release();
|
|
|
|
if (!resourceAllocated){
|
|
|
|
if (telemetryBufHeadToCac.refCnt() > 0) {
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
commonDataBuf.end();
|
|
|
|
|
|
|
|
controlDataBuf.end();
|
|
|
|
|
|
|
|
bindDataBuf.end();
|
|
|
|
|
|
|
|
queryDataBuf.end();
|
|
|
|
|
|
|
|
routeDataBuf.end();
|
|
|
|
|
|
|
|
if (telemetryBufHeadToCac!= null && telemetryBufHeadToCac.refCnt() > 0) {
|
|
|
|
telemetryBufHeadToCac.release(telemetryBufHeadToCac.refCnt());
|
|
|
|
telemetryBufHeadToCac.release(telemetryBufHeadToCac.refCnt());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
previousControl.end();
|
|
|
|
previousControl.end();
|
|
|
@ -136,100 +154,203 @@ public class HaborClient extends BaseClient {
|
|
|
|
previousRouteBind.end();
|
|
|
|
previousRouteBind.end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**只通过get读数,不改变readerIndex和writerIndex, 也不可更改refCnt*/
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 只通过get读数,不改变readerIndex和writerIndex, 也不可更改refCnt
|
|
|
|
|
|
|
|
*/
|
|
|
|
public void process(ByteBuf msg) {
|
|
|
|
public void process(ByteBuf msg) {
|
|
|
|
if (msg.getByte(0) != HEAD[0] && msg.getByte(1) != HEAD[1]) {
|
|
|
|
if (msg.getByte(0) != HEAD[0] && msg.getByte(1) != HEAD[1]) {
|
|
|
|
return; // 帧头错误,抛弃
|
|
|
|
return; // 帧头错误,抛弃
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!processInjectResponse(msg)) {
|
|
|
|
if (!processInjectResponse(msg)) {
|
|
|
|
|
|
|
|
// 如果消息未处理,则发送给中心指控
|
|
|
|
sendToCac(msg.retain()); // 外面SimpleChannelInboundHandler会自动release msg, 所以这里需要retain一次
|
|
|
|
sendToCac(msg.retain()); // 外面SimpleChannelInboundHandler会自动release msg, 所以这里需要retain一次
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**注入回报帧处理*/
|
|
|
|
|
|
|
|
protected boolean processInjectResponse(ByteBuf msg) {
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**发送常发帧*/
|
|
|
|
|
|
|
|
protected void writeCommonData() {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 注入回报帧处理
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
protected abstract boolean processInjectResponse(ByteBuf msg);
|
|
|
|
|
|
|
|
|
|
|
|
/**向飞控发送控制指令*/
|
|
|
|
/**
|
|
|
|
public void writeControlCommand(byte commandCode, String uavControlUniId) {}
|
|
|
|
* 发送常发帧
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
protected abstract void writeCommonData();
|
|
|
|
|
|
|
|
|
|
|
|
/**向飞控发送参数装订指令*/
|
|
|
|
/**
|
|
|
|
public void writeParamBindCommand(byte commandCode, byte[] commandContent, String controlUniId) {}
|
|
|
|
* 向飞控发送控制指令
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public abstract void writeControlCommand(byte commandCode, String uavControlUniId);
|
|
|
|
|
|
|
|
|
|
|
|
/**向飞控发送参数查询指令*/
|
|
|
|
/**
|
|
|
|
public void writeParamQueryCommand(byte commandCode, byte[] commandContent, String controlUniId) {}
|
|
|
|
* 向飞控发送参数装订指令
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public abstract void writeParamBindCommand(byte commandCode, byte[] commandContent, String controlUniId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 向飞控发送参数查询指令
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public abstract void writeParamQueryCommand(byte commandCode, byte[] commandContent, String controlUniId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 向飞控发送航线装订指令
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public abstract void writeRouteBindCommand(byte commandCode, List<byte[]> routeInfoList, String controlUniId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 启动定时任务常发数据帧
|
|
|
|
|
|
|
|
protected void startSendCommonData() {
|
|
|
|
|
|
|
|
// scheduledFuture = channel.eventLoop().scheduleAtFixedRate(
|
|
|
|
|
|
|
|
// this::writeCommonData, 0, targetPeriod, TimeUnit.MILLISECONDS);
|
|
|
|
|
|
|
|
// // 检查任务是否成功启动
|
|
|
|
|
|
|
|
// if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
|
|
|
|
|
|
|
|
// log.info("[cac] 开始向哈勃终端({})发送常发帧", shortInfo());
|
|
|
|
|
|
|
|
// needToSendCommonData.compareAndSet(false, true);
|
|
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
|
|
// log.info("[cac] 哈勃终端({})发送常发帧启动失败", shortInfo());
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
needToSendCommonData.set(true);
|
|
|
|
|
|
|
|
lastSendTime = System.currentTimeMillis();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scheduledFuture = channel.eventLoop().submit(new Runnable() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void run() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
if (!needToSendCommonData.get() || !channel.isActive()) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
long currentTime = System.currentTimeMillis();
|
|
|
|
|
|
|
|
long elapsed = currentTime - lastSendTime;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (elapsed >= targetPeriod) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 批量发送逻辑,如果延迟太大,可以考虑补发
|
|
|
|
|
|
|
|
int missedFrames = (int) (elapsed / targetPeriod);
|
|
|
|
|
|
|
|
if (missedFrames > 2) { // 限制补发帧数
|
|
|
|
|
|
|
|
log.warn("常发帧延迟: {}ms", elapsed - targetPeriod);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
writeCommonData();
|
|
|
|
|
|
|
|
lastSendTime = currentTime;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 使用schedule而不是立即execute,给其他任务执行的机会
|
|
|
|
|
|
|
|
channel.eventLoop().schedule(this,
|
|
|
|
|
|
|
|
Math.max(MIN_SCHEDULE_DELAY, targetPeriod / 2),
|
|
|
|
|
|
|
|
TimeUnit.MILLISECONDS);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// 延迟剩余时间后再次调度
|
|
|
|
|
|
|
|
channel.eventLoop().schedule(this,
|
|
|
|
|
|
|
|
Math.max(MIN_SCHEDULE_DELAY, targetPeriod - elapsed),
|
|
|
|
|
|
|
|
TimeUnit.MILLISECONDS);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.error("[cac] {} 常发帧调度异常: {}", shortInfo(), e.getMessage());
|
|
|
|
|
|
|
|
// 发生异常时,延迟一段时间后重试
|
|
|
|
|
|
|
|
if (needToSendCommonData.get() && channel.isActive()) {
|
|
|
|
|
|
|
|
channel.eventLoop().schedule(this, 500, TimeUnit.MILLISECONDS);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.info("[cac] 开始向哈勃终端({})发送常发帧, 频率:{}帧/秒", shortInfo(), commonDataFreq);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**向飞控发送航线装订指令*/
|
|
|
|
|
|
|
|
public void writeRouteBindCommand(byte commandCode, List<byte[]> routeInfoList, String controlUniId) {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**设置当前发送数据*/
|
|
|
|
|
|
|
|
protected void setCurrentSendData(DataByteBuf dataByteBuf) {
|
|
|
|
protected void setCurrentSendData(DataByteBuf dataByteBuf) {
|
|
|
|
|
|
|
|
setCurrentSendData(dataByteBuf, DEFAULT_COMMON_DATA_FREQ);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 设置当前发送数据
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
protected void setCurrentSendData(DataByteBuf dataByteBuf, int freq) {
|
|
|
|
dataByteBuf.resetSendCount();
|
|
|
|
dataByteBuf.resetSendCount();
|
|
|
|
dataBufToSend = dataByteBuf;
|
|
|
|
dataBufToSend = dataByteBuf;
|
|
|
|
|
|
|
|
if (freq != commonDataFreq) {
|
|
|
|
|
|
|
|
adjustSendFrequency(freq);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**恢复常发帧数据*/
|
|
|
|
|
|
|
|
|
|
|
|
// 调整常发帧发送频率
|
|
|
|
|
|
|
|
protected void adjustSendFrequency(int newFreq) {
|
|
|
|
|
|
|
|
if (newFreq <= 0) {
|
|
|
|
|
|
|
|
throw new IllegalArgumentException("频率必须大于0");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
commonDataFreq = newFreq;
|
|
|
|
|
|
|
|
targetPeriod = 1000 / newFreq;
|
|
|
|
|
|
|
|
log.info("[cac] {} 调整发送频率为 {} 帧/秒", shortInfo(), newFreq);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 恢复常发帧数据
|
|
|
|
|
|
|
|
*/
|
|
|
|
protected void switchToCommonData() {
|
|
|
|
protected void switchToCommonData() {
|
|
|
|
setCurrentSendData(commonDataBuf);
|
|
|
|
setCurrentSendData(commonDataBuf, DEFAULT_COMMON_DATA_FREQ);
|
|
|
|
dataBufToSend.resetSendCount();
|
|
|
|
dataBufToSend.resetSendCount();
|
|
|
|
log.info("[cac] {} 设置当前发送数据为常发数据帧", shortInfo());
|
|
|
|
log.info("[cac] {} 设置当前发送数据为常发数据帧", shortInfo());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 启动定时任务常发数据帧
|
|
|
|
|
|
|
|
protected void startSendCommonData() {
|
|
|
|
|
|
|
|
int period = 1000 / commonDataFreq; // 每帧间隔ms
|
|
|
|
|
|
|
|
scheduledFuture = channel.eventLoop().scheduleAtFixedRate(
|
|
|
|
|
|
|
|
this::writeCommonData, 0, period, TimeUnit.MILLISECONDS);
|
|
|
|
|
|
|
|
// 检查任务是否成功启动
|
|
|
|
|
|
|
|
if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
|
|
|
|
|
|
|
|
log.info("[cac] 开始向哈勃终端({})发送常发帧", shortInfo());
|
|
|
|
|
|
|
|
needToSendCommonData.compareAndSet(false, true);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.info("[cac] 哈勃终端({})发送常发帧启动失败", shortInfo());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 停止定时任务常发数据帧
|
|
|
|
// 停止定时任务常发数据帧
|
|
|
|
protected void stopSendCommonData() {
|
|
|
|
protected void stopSendCommonData() {
|
|
|
|
|
|
|
|
needToSendCommonData.set(false);
|
|
|
|
if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
|
|
|
|
if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
|
|
|
|
scheduledFuture.cancel(true); // 取消任务并尝试中断
|
|
|
|
scheduledFuture.cancel(true); // 取消任务并尝试中断
|
|
|
|
needToSendCommonData.compareAndSet(true, false);
|
|
|
|
scheduledFuture = null;
|
|
|
|
log.info("[cac] 停止向哈勃终端({})发送常发帧", shortInfo());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log.info("[cac] 停止向哈勃终端({})发送常发帧", shortInfo());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected boolean isNeedToSendCommonData() {
|
|
|
|
protected boolean isNeedToSendCommonData() {
|
|
|
|
return needToSendCommonData.get();
|
|
|
|
return needToSendCommonData.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**暂停发送常发帧*/
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 暂停发送常发帧
|
|
|
|
|
|
|
|
*/
|
|
|
|
protected void pauseSendCommonData() {
|
|
|
|
protected void pauseSendCommonData() {
|
|
|
|
// needToSendCommonData.set(false);
|
|
|
|
needToSendCommonData.set(false);
|
|
|
|
log.info("[cac] 暂停向哈勃终端({})发送常发帧", shortInfo());
|
|
|
|
log.info("[cac] 暂停向哈勃终端({})发送常发帧", shortInfo());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**恢复发送常发帧*/
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 恢复发送常发帧
|
|
|
|
|
|
|
|
*/
|
|
|
|
protected void resumeSendCommonData() {
|
|
|
|
protected void resumeSendCommonData() {
|
|
|
|
// needToSendCommonData.set(true);
|
|
|
|
needToSendCommonData.set(true);
|
|
|
|
log.info("[cac] 恢复向哈勃终端({})发送常发帧", shortInfo());
|
|
|
|
log.info("[cac] 恢复向哈勃终端({})发送常发帧", shortInfo());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 发送飞控数据到中心指控
|
|
|
|
* 发送飞控数据到中心指控
|
|
|
|
|
|
|
|
*
|
|
|
|
* @param srcBuf 原始遥测ByteBuf
|
|
|
|
* @param srcBuf 原始遥测ByteBuf
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public void sendToCac(ByteBuf srcBuf) {
|
|
|
|
public void sendToCac(ByteBuf srcBuf) {
|
|
|
|
telemetryBufHeadToCac.writerIndex(cacHeadLength-6);
|
|
|
|
telemetryBufHeadToCac.writerIndex(cacHeadLength - 6);
|
|
|
|
telemetryBufHeadToCac.writeShort(cacFrameIdx.getAndIncrement());
|
|
|
|
telemetryBufHeadToCac.writeShort(cacFrameIdx.getAndIncrement());
|
|
|
|
telemetryBufHeadToCac.writeInt(srcBuf.readableBytes());
|
|
|
|
telemetryBufHeadToCac.writeInt(srcBuf.readableBytes());
|
|
|
|
ByteBuf telemetryBufToCac = Unpooled.wrappedBuffer(telemetryBufHeadToCac.retain(), srcBuf); // 遥测数据组合
|
|
|
|
ByteBuf telemetryBufToCac = Unpooled.wrappedBuffer(telemetryBufHeadToCac.retain(), srcBuf); // 遥测数据组合
|
|
|
|
CacClient.write(telemetryBufToCac);
|
|
|
|
ChannelFuture future = CacClient.write(telemetryBufToCac);
|
|
|
|
|
|
|
|
if (future != null) {
|
|
|
|
|
|
|
|
// future.addListener((ChannelFuture f) -> {
|
|
|
|
|
|
|
|
// if (!f.isSuccess()) {
|
|
|
|
|
|
|
|
// telemetryBufToCac.release();
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
telemetryBufToCac.release();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**给数据添加CRC16校验*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 给数据添加CRC16校验
|
|
|
|
|
|
|
|
*/
|
|
|
|
protected void addCRC16(ByteBuf dataBuf) {
|
|
|
|
protected void addCRC16(ByteBuf dataBuf) {
|
|
|
|
ByteBuf slice = dataBuf.slice(2, 28);// 校验第3-30位,共28个字节
|
|
|
|
ByteBuf slice = dataBuf.slice(2, 28);// 校验第3-30位,共28个字节
|
|
|
|
dataBuf.writerIndex(30);
|
|
|
|
dataBuf.writerIndex(30);
|
|
|
@ -237,56 +358,98 @@ public class HaborClient extends BaseClient {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 装订查询回报对象
|
|
|
|
|
|
|
|
*/
|
|
|
|
public static abstract class UavQueryResultParam {
|
|
|
|
public static abstract class UavQueryResultParam {
|
|
|
|
public abstract String toJsonStr() throws IOException;
|
|
|
|
public abstract String toJsonStr() throws IOException;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**Cac起飞参数查询查询回报,具体定义见各型号子类*/
|
|
|
|
|
|
|
|
public static abstract class UavTakeOffParamQueryResultParam extends UavQueryResultParam {}
|
|
|
|
/**
|
|
|
|
/**Cac重量查询回报,具体定义见各型号子类*/
|
|
|
|
* Cac起飞参数查询查询回报,具体定义见各型号子类
|
|
|
|
public static abstract class UavWeightQueryResultParam extends UavQueryResultParam {}
|
|
|
|
*/
|
|
|
|
protected static class DataByteBuf{
|
|
|
|
public static abstract class UavTakeOffParamQueryResultParam extends UavQueryResultParam {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Cac重量查询回报,具体定义见各型号子类
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static abstract class UavWeightQueryResultParam extends UavQueryResultParam {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 数据发送对象
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
protected static class DataByteBuf {
|
|
|
|
protected ByteBuf buf;
|
|
|
|
protected ByteBuf buf;
|
|
|
|
private AtomicInteger sendCount = new AtomicInteger(0);
|
|
|
|
private AtomicInteger sendCount = new AtomicInteger(0);
|
|
|
|
public DataByteBuf(int frameSize) {buf = PooledByteBufAllocator.DEFAULT.buffer(frameSize);}
|
|
|
|
|
|
|
|
public void release() {
|
|
|
|
public DataByteBuf(int frameSize) {
|
|
|
|
|
|
|
|
buf = PooledByteBufAllocator.DEFAULT.buffer(frameSize);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void end() {
|
|
|
|
if (buf.refCnt() > 0) {
|
|
|
|
if (buf.refCnt() > 0) {
|
|
|
|
buf.release(buf.refCnt());
|
|
|
|
buf.release(buf.refCnt());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void resetSendCount() {
|
|
|
|
public void resetSendCount() {
|
|
|
|
sendCount.set(0);
|
|
|
|
sendCount.set(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public int addSendCount() {
|
|
|
|
public int addSendCount() {
|
|
|
|
return sendCount.incrementAndGet();
|
|
|
|
return sendCount.incrementAndGet();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public int getSendCount() {
|
|
|
|
public int getSendCount() {
|
|
|
|
return sendCount.get();
|
|
|
|
return sendCount.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected static class CommonDataBuf extends DataByteBuf{
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 常发帧
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
protected static class CommonDataBuf extends DataByteBuf {
|
|
|
|
public CommonDataBuf(int frameSize) {
|
|
|
|
public CommonDataBuf(int frameSize) {
|
|
|
|
super(frameSize);
|
|
|
|
super(frameSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
protected static class ControlDataBuf extends DataByteBuf{
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 控制指令帧
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
protected static class ControlDataBuf extends DataByteBuf {
|
|
|
|
public int needCount = 10; // 默认帧数
|
|
|
|
public int needCount = 10; // 默认帧数
|
|
|
|
|
|
|
|
|
|
|
|
public ControlDataBuf(int frameSize) {
|
|
|
|
public ControlDataBuf(int frameSize) {
|
|
|
|
super(frameSize);
|
|
|
|
super(frameSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
protected static class BindDataBuf extends DataByteBuf{
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 数据装订帧
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
protected static class BindDataBuf extends DataByteBuf {
|
|
|
|
public BindDataBuf(int frameSize) {
|
|
|
|
public BindDataBuf(int frameSize) {
|
|
|
|
super(frameSize);
|
|
|
|
super(frameSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
protected static class QueryDataBuf extends DataByteBuf{
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 数据查询帧
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
protected static class QueryDataBuf extends DataByteBuf {
|
|
|
|
public QueryDataBuf(int frameSize) {
|
|
|
|
public QueryDataBuf(int frameSize) {
|
|
|
|
super(frameSize);
|
|
|
|
super(frameSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
protected static class RouteDataBuf extends DataByteBuf{
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 航线数据帧
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
protected static class RouteDataBuf extends DataByteBuf {
|
|
|
|
public RouteDataBuf(int frameSize) {
|
|
|
|
public RouteDataBuf(int frameSize) {
|
|
|
|
super(frameSize);
|
|
|
|
super(frameSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|