[v0.0.1] 中心指控指令下发与飞控回复结果判断处理、超时判定

master
shiyi 2 months ago
parent 5f94268b3b
commit 9678a959ec

@ -167,26 +167,21 @@ public class CacHpApi {
final String gcsSignApi = HTFP_PATH + "/notifyUavCommand";
return postRequest(gcsSignApi, body);
}
public static String uavControlReply(String body) {
final String gcsSignApi = HTFP_PATH + "/replyUavControlRight";
return postRequest(gcsSignApi, body);
}
public static String uavControlReceive(String body) {
final String gcsSignApi = HTFP_PATH + "/receiveUavControlRight";
/**
*
*/
public static String uavParamQueryResultNotify(String body) {
final String gcsSignApi = HTFP_PATH + "/uavParamQueryResultNotify";
return postRequest(gcsSignApi, body);
}
public static String queryUavId(String body) {
final String gcsSignApi = HTFP_PATH + "/queryUavIdByFlightControlSnAndType";
/**
*
*/
public static String uavParamBindResultNotify(String body) {
final String gcsSignApi = HTFP_PATH + "/uavParamBindResultNotify";
return postRequest(gcsSignApi, body);
}
public static String queryUavMapping(String body) {
final String gcsSignApi = HTFP_PATH + "/queryUavIdAndFlightControlSnMapping";
return postRequest(gcsSignApi, body);
}
public static List<DirectControlUavParam> queryAllCacDirectControlUavList(String body) {
final String gcsSignApi = HTFP_PATH + "/queryAllCacDirectControlUavList";

@ -1,42 +0,0 @@
package com.platform.cac.tcp.message.dataframe.receive;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.util.ByteUtils;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import java.nio.ByteBuffer;
@Getter
@ToString
@Slf4j
public class CacReceiveUavControlMessage extends RemoteTcpBaseDataFrame {
private byte receiveGcsIdLength;
private String receiveGcsId;
private byte uavControlAccept;
private byte uavControlAppplyIdLength;
private String uavControlApplyId;
public CacReceiveUavControlMessage(RemoteTcpBaseDataFrame data) {
super(data);
ByteBuffer buffer = ByteBuffer.allocate(data.getReadableDataBytesLength()).put(data.getReadableDataBytes());
buffer.flip();
try {
receiveGcsIdLength = buffer.get();
receiveGcsId = ByteUtils.getString(buffer, receiveGcsIdLength);
uavControlAccept = buffer.get();
uavControlAppplyIdLength = buffer.get();
uavControlApplyId = ByteUtils.getString(buffer, uavControlAppplyIdLength);
} catch (Exception e){
log.error("中心指控-控制权接收数据解析异常");
e.printStackTrace();
}
}
}

@ -1,46 +0,0 @@
package com.platform.cac.tcp.message.dataframe.receive;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.util.ByteUtils;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import java.nio.ByteBuffer;
@Getter
@ToString
@Slf4j
public class CacReplyUavControlMessage extends RemoteTcpBaseDataFrame {
private byte replyGcsIdLength;
private String replyGcsId;
private byte uavControlApprove;
private byte uavControlApplyIdLength;
private String uavControlApplyId;
public CacReplyUavControlMessage(RemoteTcpBaseDataFrame data) {
super(data);
ByteBuffer buffer = ByteBuffer.allocate(data.getReadableDataBytesLength()).put(data.getReadableDataBytes());
buffer.flip();
try {
replyGcsIdLength = buffer.get();
replyGcsId = ByteUtils.getString(buffer, replyGcsIdLength);
uavControlApprove = buffer.get();
uavControlApplyIdLength = buffer.get();
uavControlApplyId = ByteUtils.getString(buffer, uavControlApplyIdLength);
} catch (Exception e) {
log.error("中心指控-控制权回复数据解析异常");
e.printStackTrace();
}
}
}

@ -1,42 +0,0 @@
package com.platform.cac.tcp.message.dataframe.receive;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.util.ByteUtils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.nio.ByteBuffer;
@Getter
@Slf4j
public class CacUavControlApplyMessage extends RemoteTcpBaseDataFrame {
private byte applyGcsIdLength;
private String applyGcsId;
private byte uavControlApplyReasonLength;
private String uavControlApplyReason;
private byte uavControlApplyIdLength;
private String uavControlApplyId;
public CacUavControlApplyMessage(RemoteTcpBaseDataFrame data){
super(data);
ByteBuffer buffer = ByteBuffer.allocate(data.getReadableDataBytesLength()).put(data.getReadableDataBytes());
buffer.flip();
try {
applyGcsIdLength = buffer.get();
applyGcsId = ByteUtils.getString(buffer, applyGcsIdLength);
uavControlApplyReasonLength = buffer.get();
uavControlApplyReason = ByteUtils.getString(buffer, uavControlApplyReasonLength);
uavControlApplyIdLength = buffer.get();
uavControlApplyId = ByteUtils.getString(buffer, uavControlApplyIdLength);
} catch (Exception e){
log.error("中心指控-控制权申请数据解析异常");
e.printStackTrace();
}
}
}

@ -0,0 +1,44 @@
package com.platform.cac.tcp.message.dataframe.receive;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.util.ByteUtils;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import java.nio.ByteBuffer;
@Slf4j
@Getter
@ToString
public class CacUavParamBindMessage extends RemoteTcpBaseDataFrame {
private byte uavParamBindTypeLength;
private byte[] uavParamBindType;
private byte commandCode;
private byte[] commandContent = new byte[15]; // 15~29
private byte[] crc16 = new byte[2];
private byte uavControlUniIdLength;
private String uavControlUniId;
public CacUavParamBindMessage(RemoteTcpBaseDataFrame data){
super(data);
ByteBuffer buffer = ByteBuffer.allocate(data.getReadableDataBytesLength()).put(data.getReadableDataBytes());
buffer.flip();
try {
uavParamBindTypeLength = buffer.get();
uavParamBindType = new byte[uavParamBindTypeLength];
buffer.get(uavParamBindType);
commandCode = buffer.get();
buffer.get(commandContent);
buffer.get(crc16);
uavControlUniIdLength=buffer.get();
uavControlUniId = ByteUtils.getString(buffer, uavControlUniIdLength);
} catch (Exception e) {
log.error("中心指控-飞控参数装订指令数据解析异常");
e.printStackTrace();
}
}
}

@ -0,0 +1,44 @@
package com.platform.cac.tcp.message.dataframe.receive;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.util.ByteUtils;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import java.nio.ByteBuffer;
@Slf4j
@Getter
@ToString
public class CacUavParamQueryMessage extends RemoteTcpBaseDataFrame {
private byte uavParamQueryTypeLength;
private byte[] uavParamQueryType;
private byte commandCode;
private byte[] commandContent = new byte[15]; // 15~29
private byte[] crc16 = new byte[2];
private byte uavControlUniIdLength;
private String uavControlUniId;
public CacUavParamQueryMessage(RemoteTcpBaseDataFrame data){
super(data);
ByteBuffer buffer = ByteBuffer.allocate(data.getReadableDataBytesLength()).put(data.getReadableDataBytes());
buffer.flip();
try {
uavParamQueryTypeLength = buffer.get();
uavParamQueryType = new byte[uavParamQueryTypeLength];
buffer.get(uavParamQueryType);
commandCode = buffer.get();
buffer.get(commandContent);
buffer.get(crc16);
uavControlUniIdLength=buffer.get();
uavControlUniId = ByteUtils.getString(buffer, uavControlUniIdLength);
} catch (Exception e) {
log.error("中心指控-飞控参数查询指令解析异常");
e.printStackTrace();
}
}
}

@ -0,0 +1,47 @@
package com.platform.cac.tcp.message.dataframe.receive;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.util.ByteUtils;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import java.nio.ByteBuffer;
@Slf4j
@Getter
@ToString
public class CacUavRouteBindMessage extends RemoteTcpBaseDataFrame {
private byte uavParamBindTypeLength;
private byte[] uavParamBindType;
private byte commandCode;
private byte routePointNum;
private byte[] routePointInfo;
private byte[] crc16 = new byte[2];
private byte uavControlUniIdLength;
private String uavControlUniId;
public CacUavRouteBindMessage(RemoteTcpBaseDataFrame data){
super(data);
ByteBuffer buffer = ByteBuffer.allocate(data.getReadableDataBytesLength()).put(data.getReadableDataBytes());
buffer.flip();
try {
uavParamBindTypeLength = buffer.get();
uavParamBindType = new byte[uavParamBindTypeLength];
buffer.get(uavParamBindType);
commandCode = buffer.get();
routePointNum = buffer.get();
routePointInfo = new byte[routePointNum * 16]; // 14~29
buffer.get(routePointInfo);
buffer.get(crc16);
uavControlUniIdLength=buffer.get();
uavControlUniId = ByteUtils.getString(buffer, uavControlUniIdLength);
} catch (Exception e) {
log.error("中心指控-航线装订数据解析异常");
e.printStackTrace();
}
}
}

@ -1,21 +0,0 @@
package com.platform.cac.tcp.message.dataframe.send;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import lombok.Data;
/**
* @Author sunjipeng
* @Date 2023/6/14
* @Description
*/
@Data
public class TcpFlightPlanReplyRequest extends RemoteTcpBaseDataFrame {
private byte applyFlightPlanIdLength;
private String applyFlightPlanId;
private byte replyFlightPlanIdLength;
private String replyFlightPlanId;
private byte flightPlanPass;
}

@ -1,20 +0,0 @@
package com.platform.cac.tcp.message.dataframe.send;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import lombok.Data;
/**
* @Author sunjipeng
* @Date 2023/6/28
* @Description
*/
@Data
public class TcpFlightPlanRevokeRequest extends RemoteTcpBaseDataFrame {
private byte applyFlightPlanIdLength;
private String applyFlightPlanId;
private byte revokeReasonLength;
private String revokeReason;
}

@ -1,21 +0,0 @@
package com.platform.cac.tcp.message.dataframe.send;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import lombok.Data;
/**
* @Author sunjipeng
* @Date 2023/6/14
* @Description
*/
@Data
public class TcpFlyReplyRequest extends RemoteTcpBaseDataFrame {
private byte applyFlyIdLength;
private String applyFlyId;
private byte replyFlyIdLength;
private String replyFlyId;
private byte flyPass;
}

@ -1,19 +0,0 @@
package com.platform.cac.tcp.message.dataframe.send;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import lombok.Data;
/**
* @Author sunjipeng
* @Date 2023/6/14
* @Description
*/
@Data
public class TcpReceiveAlarmRequest extends RemoteTcpBaseDataFrame {
private int alarmLevel;
private byte contentLength;
private String content;
private long effectTime;
}

@ -1,18 +0,0 @@
package com.platform.cac.tcp.message.dataframe.send;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import lombok.Data;
/**
* @Author sunjipeng
* @Date 2023/6/14
* @Description
*/
@Data
public class TcpReceiveAtcRequest extends RemoteTcpBaseDataFrame {
private int atcType;
private long effectTime;
}

@ -32,20 +32,20 @@ public class CacUavCommandIssuedHandler implements IRemoteMessageHandler {
String uavId = uavCommand.getUavId();
String haborSn = HaborUavMap.getHaborSnByUavId(uavId);
if (haborSn == null){
log.error("[cac] 中心指控指令下发失败未找到UavId={}对应的哈勃编号", uavId);
log.error("[cac] 中心指控控制指令下发失败未找到UavId={}对应的哈勃编号", uavId);
return;
}
byte[] uavCommandCodeId = uavCommand.getUavCommandCodeId();
if (uavCommandCodeId.length!=1) {
log.error("[cac] 中心指控指令下发失败,指令码长度错误:{}", ByteUtils.bytes2HexString(uavCommandCodeId));
log.error("[cac] 中心指控控制指令下发失败,指令码长度错误:{}", ByteUtils.bytes2HexString(uavCommandCodeId));
return;
}
String uavControlUniId = uavCommand.getUavControlUniId();
log.info("[cac] 中心指控下发指令...{}", uavCommand);
log.info("[cac] 中心指控下发控制指令...{}", uavCommand);
HaborClient client = (HaborClient) ClientManager.getClient(haborSn);
client.writeControlCommand(uavControlUniId, uavCommandCodeId[0]);
client.writeControlCommand(uavCommandCodeId[0], uavControlUniId);
} else {
log.warn("[cac] 当前服务未连接中心指控无法下发指令");
log.warn("[cac] 当前服务未连接中心指控无法下发控制指令");
}
}
@Override

@ -1,54 +0,0 @@
package com.platform.cac.tcp.message.handler;
import com.platform.cac.GcsService;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.cac.tcp.message.dataframe.receive.CacUavCommandMessage;
import com.platform.info.enums.RemoteFrameEnum;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @Author : shiyi
* @Date : 2024/1/24 17:38
* @Description :
*/
@Component
@Slf4j
public class CacUavCommandResultHandler implements IRemoteMessageHandler {
@Resource
GcsService gcsService;
@Override
public void execute(Channel channel, RemoteTcpBaseDataFrame remoteTcpBaseDataFrame) {
if (gcsService.isSignIn()){
CacUavCommandMessage uavCommand = new CacUavCommandMessage(remoteTcpBaseDataFrame);
log.debug("向地面站查询指令...{}", uavCommand);
// GcsService.queryCommandUniId= uavCommand.getUavControlUniId();
// log.debug("queryCommandUniId Info: {}", GcsService.queryCommandUniId);
queryUavCommandResult(uavCommand);
} else {
log.warn("无法查询指令");
}
}
/**
*
* @param uavCommand
*/
private void queryUavCommandResult(CacUavCommandMessage uavCommand) {
// String uavId = uavCommand.getUavId();
// int fkUavId = UavIdMap.getFkId(uavId);
// ByteBuf bufToGcs = Unpooled.buffer();
// bufToGcs.writeByte((byte) fkUavId);
// bufToGcs.writeByte(uavCommand.getUavCommandCodeIdLength());
// bufToGcs.writeBytes(uavCommand.getUavCommandCodeId());
// gcsService.sendToGcs(GcsFrameEnum.QUERY_COMMAND.getCode(), bufToGcs);
}
@Override
public RemoteFrameEnum getFrameType() {
return RemoteFrameEnum.UAV_COMMAND_QUERY;
}
}

@ -0,0 +1,75 @@
package com.platform.cac.tcp.message.handler;
import com.platform.cac.GcsService;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.cac.tcp.message.dataframe.receive.CacUavParamBindMessage;
import com.platform.info.enums.RemoteFrameEnum;
import com.platform.info.mapping.HaborUavMap;
import com.platform.service.clientmanage.ClientManager;
import com.platform.service.clientmanage.HaborClient;
import com.platform.util.ByteUtils;
import com.platform.util.CRCUtil;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Arrays;
/**
* @Author : shiyi
* @Date : 2025/1/21 10:38
* @Description :
*/
@Component
@Slf4j
public class CacUavParamBindHandler implements IRemoteMessageHandler {
@Resource
GcsService gcsService;
@Override
public void execute(Channel channel, RemoteTcpBaseDataFrame remoteTcpBaseDataFrame) {
if (gcsService.isSignIn()){
CacUavParamBindMessage uavCommand = new CacUavParamBindMessage(remoteTcpBaseDataFrame);
String uavId = uavCommand.getUavId();
String haborSn = HaborUavMap.getHaborSnByUavId(uavId);
if (haborSn == null){
log.error("[cac] 中心指控参数装订指令下发失败未找到UavId={}对应的哈勃编号", uavId);
return;
}
byte commandCode = uavCommand.getCommandCode();
byte[] commandContent = uavCommand.getCommandContent();
byte[] command14_29 = new byte[16];
command14_29[0] = commandCode;
System.arraycopy(commandContent, 0, command14_29, 1, 15);
if (Arrays.equals(uavCommand.getCrc16(), CRCUtil.getCRCfromGcsTelemetryData(command14_29, 0, 16))) {
log.error("[cac] 中心指控参数装订指令下发失败CRC校验失败");
return;
}
String uavControlUniId = uavCommand.getUavControlUniId();
log.info("[cac] 中心指控下发参数装订指令...{}", uavCommand);
HaborClient client = (HaborClient) ClientManager.getClient(haborSn);
client.writeParamBindCommand(commandCode, commandContent, uavControlUniId);
} else {
log.warn("[cac] 当前服务未连接中心指控无法下发参数装订指令");
}
}
/**
*
* @param uavCommand
*/
private void queryUavCommandResult(CacUavParamBindMessage uavCommand) {
// String uavId = uavCommand.getUavId();
// int fkUavId = UavIdMap.getFkId(uavId);
// ByteBuf bufToGcs = Unpooled.buffer();
// bufToGcs.writeByte((byte) fkUavId);
// bufToGcs.writeByte(uavCommand.getUavCommandCodeIdLength());
// bufToGcs.writeBytes(uavCommand.getUavCommandCodeId());
// gcsService.sendToGcs(GcsFrameEnum.QUERY_COMMAND.getCode(), bufToGcs);
}
@Override
public RemoteFrameEnum getFrameType() {
return RemoteFrameEnum.UAV_COMMAND_QUERY;
}
}

@ -0,0 +1,62 @@
package com.platform.cac.tcp.message.handler;
import com.platform.cac.GcsService;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.cac.tcp.message.dataframe.receive.CacUavParamBindMessage;
import com.platform.cac.tcp.message.dataframe.receive.CacUavParamQueryMessage;
import com.platform.info.enums.RemoteFrameEnum;
import com.platform.info.mapping.HaborUavMap;
import com.platform.service.clientmanage.ClientManager;
import com.platform.service.clientmanage.HaborClient;
import com.platform.util.CRCUtil;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Arrays;
/**
* @Author : shiyi
* @Date : 2025/1/21 10:38
* @Description :
*/
@Component
@Slf4j
public class CacUavParamQueryHandler implements IRemoteMessageHandler {
@Resource
GcsService gcsService;
@Override
public void execute(Channel channel, RemoteTcpBaseDataFrame remoteTcpBaseDataFrame) {
if (gcsService.isSignIn()){
CacUavParamQueryMessage uavCommand = new CacUavParamQueryMessage(remoteTcpBaseDataFrame);
String uavId = uavCommand.getUavId();
String haborSn = HaborUavMap.getHaborSnByUavId(uavId);
if (haborSn == null){
log.error("[cac] 中心指控参数查询指令下发失败未找到UavId={}对应的哈勃编号", uavId);
return;
}
byte commandCode = uavCommand.getCommandCode();
byte[] commandContent = uavCommand.getCommandContent();
byte[] command14_29 = new byte[16];
command14_29[0] = commandCode;
System.arraycopy(commandContent, 0, command14_29, 1, 15);
if (Arrays.equals(uavCommand.getCrc16(), CRCUtil.getCRCfromGcsTelemetryData(command14_29, 0, 16))) {
log.error("[cac] 中心指控参数查询指令下发失败CRC校验失败");
return;
}
String uavControlUniId = uavCommand.getUavControlUniId();
log.info("[cac] 中心指控下发参数查询指令...{}", uavCommand);
HaborClient client = (HaborClient) ClientManager.getClient(haborSn);
client.writeParamQueryCommand(commandCode, commandContent, uavControlUniId);
} else {
log.warn("[cac] 当前服务未连接中心指控无法下发参数查询指令");
}
}
@Override
public RemoteFrameEnum getFrameType() {
return RemoteFrameEnum.UAV_COMMAND_QUERY;
}
}

@ -0,0 +1,79 @@
package com.platform.cac.tcp.message.handler;
import com.platform.cac.GcsService;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.cac.tcp.message.dataframe.receive.CacUavParamBindMessage;
import com.platform.cac.tcp.message.dataframe.receive.CacUavRouteBindMessage;
import com.platform.info.enums.RemoteFrameEnum;
import com.platform.info.mapping.HaborUavMap;
import com.platform.service.clientmanage.ClientManager;
import com.platform.service.clientmanage.HaborClient;
import com.platform.util.CRCUtil;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @Author : shiyi
* @Date : 2025/1/22 11:38
* @Description : 线
*/
@Component
@Slf4j
public class CacUavRouteBindHandler implements IRemoteMessageHandler {
@Resource
GcsService gcsService;
@Override
public void execute(Channel channel, RemoteTcpBaseDataFrame remoteTcpBaseDataFrame) {
if (gcsService.isSignIn()){
CacUavRouteBindMessage uavCommand = new CacUavRouteBindMessage(remoteTcpBaseDataFrame);
String uavId = uavCommand.getUavId();
String haborSn = HaborUavMap.getHaborSnByUavId(uavId);
if (haborSn == null){
log.error("[cac] 中心指控航线装订指令下发失败未找到UavId={}对应的哈勃编号", uavId);
return;
}
byte commandCode = uavCommand.getCommandCode();
byte routePointNum = uavCommand.getRoutePointNum();
byte[] routePointInfo = uavCommand.getRoutePointInfo(); // 16 * routePointNum 个字节
if (Arrays.equals(uavCommand.getCrc16(), CRCUtil.getCRCfromGcsTelemetryData(routePointInfo, 0, routePointInfo.length))) {
log.error("[cac] 中心指控航线装订指令下发失败CRC校验失败");
return;
}
String uavControlUniId = uavCommand.getUavControlUniId();
log.info("[cac] 中心指控下发航线装订指令...{}", uavCommand);
HaborClient client = (HaborClient) ClientManager.getClient(haborSn);
List<byte[]> routeInfoList = new ArrayList<>();
for (int i = 0; i < routePointNum; i++) {
routeInfoList.add(Arrays.copyOfRange(routePointInfo, i * 16, (i + 1) * 16));
}
client.writeRouteBindCommand(commandCode, routeInfoList, uavControlUniId);
} else {
log.warn("[cac] 当前服务未连接中心指控无法下发航线装订指令");
}
}
/**
*
* @param uavCommand
*/
private void queryUavCommandResult(CacUavParamBindMessage uavCommand) {
// String uavId = uavCommand.getUavId();
// int fkUavId = UavIdMap.getFkId(uavId);
// ByteBuf bufToGcs = Unpooled.buffer();
// bufToGcs.writeByte((byte) fkUavId);
// bufToGcs.writeByte(uavCommand.getUavCommandCodeIdLength());
// bufToGcs.writeBytes(uavCommand.getUavCommandCodeId());
// gcsService.sendToGcs(GcsFrameEnum.QUERY_COMMAND.getCode(), bufToGcs);
}
@Override
public RemoteFrameEnum getFrameType() {
return RemoteFrameEnum.UAV_COMMAND_QUERY;
}
}

@ -0,0 +1,21 @@
package com.platform.info.enums;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@Getter @Slf4j
public enum CommandTypeEnum {
CONTROL(1, "开关控制"),
PARAM_BIND(2, "参数装订"),
PARAM_QUERY(3, "参数查询"),
ROUTE_BIND(4, "航线装订"),
;
private final int code;
private final String info;
CommandTypeEnum(int code, String info) {
this.code = code;
this.info = info;
}
}

@ -32,8 +32,7 @@ public class ServerService {
InMessageHandler inMessageHandler;
@Autowired
CacDataRouterHandler cacDataRouterHandler;
@Autowired
TelemetryDecoder telemetryDecoder;
private void startServer() {
//服务端需要2个线程组 boss处理客户端连接 work进行客服端连接之后的处理
log.warn("【读取配置端口】 端口 = " + config.getPort());
@ -55,7 +54,7 @@ public class ServerService {
}
channel.pipeline()
.addLast("OriginalHandler", inMessageHandler) // 原始哈勃消息解码器
.addLast("TelemetryDecoder", telemetryDecoder) // eb90数据分离
.addLast("TelemetryDecoder", new TelemetryDecoder()) // eb90数据分离
.addLast("CacDataRouter", cacDataRouterHandler); // cac数据转发
}
});

@ -0,0 +1,57 @@
package com.platform.service.clientmanage;
import com.platform.info.enums.CommandTypeEnum;
import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/** 记录一组指令执行状态(主要是航线装订),回报指令结果*/
@Slf4j
public class CommandQueueRecord extends CommandRecord {
protected Queue<byte[]> commandQueue;
public static final int WAITING_NEXT = 3; // 等待下一个节点回报
public CommandQueueRecord(CommandTypeEnum commandType, HaborClient client, int contentSize){
super(commandType, client, contentSize);
}
public void initCommandQueue(List<byte[]> commandList){
this.commandQueue = new LinkedList<>(commandList);
this.commandBuf.writerIndex(0);
this.commandBuf.writeBytes(commandQueue.peek());
}
/**
*
*
* @return
*/
public boolean completeOrWaitNext() {
this.commandQueue.poll();
if (commandQueue.isEmpty()) {
this.status = NO_COMMAND;
return true;
}
this.commandBuf.writeBytes(commandQueue.peek());
return false;
}
@Override
public void recordCommand(byte commandCode, String uniId, ByteBuf commandSlice) {
super.recordCommand(commandCode, uniId, commandSlice);
this.status = WAITING_NEXT; // 覆盖父类状态
}
@Override
public void clearCommand() {
this.commandBuf.clear();
this.commandUniId = null;
this.commandQueue = null;
this.status = NO_COMMAND;
}
}

@ -0,0 +1,179 @@
package com.platform.service.clientmanage;
import com.platform.cac.CacHpApi;
import com.platform.info.GlobalData;
import com.platform.info.enums.CommandTypeEnum;
import com.platform.info.enums.UavTypeEnum;
import com.platform.util.ByteUtils;
import com.platform.util.JSONUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
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;
/** 记录指令状态,回报指令结果*/
@Slf4j
public class CommandRecord {
private final HaborClient client;
private final CommandTypeEnum commandType;
protected byte code; // 指令码
protected ByteBuf commandBuf = null; // 指令注入内容
protected String commandUniId; // 中心指控指令唯一码
// 指令状态
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 = 5*1000; // 从下发超过5s未回报则判定为失败
protected int status;
public static final int FAILED = -1; // 指令失败
public static final int NO_COMMAND = 0; // 空闲
public static final int SUCCESS = 1; // 指令成功
public static final int WAITING_RESULT = 2; // 等待回报
// 定时任务管理
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(50); // 单线程池管理超时任务
ScheduledFuture<?> timeoutFuture = null; // 超时任务
// todo 过期时间控制
public CommandRecord(CommandTypeEnum commandType, HaborClient client) {
this.commandType = commandType;
this.client = client;
}
public CommandRecord(CommandTypeEnum commandType, HaborClient client, int contentSize) {
this.commandType = commandType;
this.client = client;
this.commandBuf = PooledByteBufAllocator.DEFAULT.buffer(contentSize);
}
public void recordCommand(byte commandCode, String uniId, ByteBuf commandSlice) {
this.code = commandCode;
this.commandBuf.clear();
this.commandBuf.writeBytes(commandSlice);
this.commandUniId = uniId;
this.status = WAITING_RESULT;
this.receiveFrameCount.set(0);
// this.startTime = System.currentTimeMillis();
// 启动一个超时检查的定时任务
// this.timeoutFuture = scheduleTimeoutCheck();
}
// 定时任务每5秒检查一次所有命令是否超时
private ScheduledFuture<?> scheduleTimeoutCheck() {
log.error("[cac] {} {}指令判断定时任务启动", client.shortInfo(), commandType.getInfo());
// 每5秒检查一次所有命令记录的超时状态
return scheduler.schedule(() -> {
if (status == WAITING_RESULT) {
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);
}
}
}, TIMEOUT_THRESHOLD, TimeUnit.MILLISECONDS); // 设置延迟时间
}
public void cancelScheduleTimeout() {
if (this.timeoutFuture != null && !this.timeoutFuture.isCancelled()) {
if (this.timeoutFuture.cancel(true)) {
log.info("[cac] {} 取消{}指令结果判断定时任务", client.shortInfo(), commandType.getInfo());
}
}
}
public void clearCommand() {
cancelScheduleTimeout();
this.commandBuf.clear();
this.commandUniId = null;
this.status = NO_COMMAND;
this.receiveFrameCount.set(0);
}
public int getState() {
return this.status;
}
public boolean commandMatch(ByteBuf commandSlice) {
return commandSlice.equals(this.commandBuf);
}
public int addReceiveFrameCount() {
return this.receiveFrameCount.incrementAndGet();
}
/**回报开关指令执行结果,目前仅收到回报时通知*/
public void notifyControlCommandResult(String uavId, boolean isSuccess) {
Map<String, Object> body = new HashMap<>();
body.put("gcsId", GlobalData.GCS_ID);
body.put("uavId", uavId);
body.put("commandCode", ByteUtils.byteToInt(this.code));
body.put("commandResult", isSuccess?0:1);
body.put("commandSource", 1);
body.put("commandUniId", this.commandUniId);
try {
CacHpApi.commandNotify(JSONUtils.obj2json(body));
} catch (IOException e) {
log.error("[cac] 开关指令回报通知失败:{}", body, e);
}
}
public void notifyParamBindCommandResult(String uavId, UavTypeEnum uavType, boolean isSuccess) {
Map<String, Object> body = new HashMap<>();
body.put("gcsId", GlobalData.GCS_ID);
body.put("uavId", uavId);
body.put("commandUniId", this.commandUniId);
body.put("commandSource", 1);
body.put("uavType", uavType.getRemoteCode());
body.put("uavParamBindCode", ByteUtils.byteToInt(this.code));
body.put("bindResult", isSuccess);
try {
CacHpApi.uavParamBindResultNotify(JSONUtils.obj2json(body));
} catch (IOException e) {
log.error("[cac] 参数装订回报通知失败:{}", body, e);
}
}
public void notifyParamQueryCommandResult(String uavId, UavTypeEnum uavType, boolean isSuccess, HaborClient.UavTakeOffParamQueryResultParam uavTakeOffParamQueryResultParam) {
Map<String, Object> body = new HashMap<>();
try {
body.put("gcsId", GlobalData.GCS_ID);
body.put("uavId", uavId);
body.put("commandUniId", this.commandUniId);
body.put("commandSource", 1);
body.put("uavType", uavType.getRemoteCode());
body.put("uavParamQueryCode", ByteUtils.byteToInt(this.code));
body.put("bindResult", isSuccess);
if (isSuccess) {
String queryResultContent = uavTakeOffParamQueryResultParam.toJsonStr();
body.put("queryResultContent", queryResultContent);
}
CacHpApi.uavParamQueryResultNotify(JSONUtils.obj2json(body));
} catch (IOException e) {
log.error("[cac] 参数装订回报通知失败:{}", body, e);
}
}
public void end() {
if (this.commandBuf != null && this.commandBuf.refCnt() > 0) {
this.commandBuf.release(this.commandBuf.refCnt());
}
}
}

@ -3,7 +3,6 @@ package com.platform.service.clientmanage;
import com.platform.cac.CacHpApi;
import com.platform.cac.tcp.CacClient;
import com.platform.info.GlobalData;
import com.platform.info.enums.ClientTypeEnum;
import com.platform.info.enums.UavTypeEnum;
import com.platform.util.*;
@ -11,16 +10,15 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.ScheduledFuture;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Author : shiyi
@ -42,19 +40,24 @@ public class HaborClient extends BaseClient {
// 数据帧内容
protected AtomicUByte frameIdx = new AtomicUByte(); // 飞控包序号
protected ByteBuf commonDataBuf; // 常发数据帧, 复用
protected ByteBuf controlDataBuf; // 开关指令数据帧, 复用
protected DataByteBuf dataBufToSend; // 默认发送常发数据帧 ; // 实际数据发送定时任务发送的数据内容发送时将引用以下dataBuf
protected CommonDataBuf commonDataBuf; // 常发数据帧, 复用
protected ControlDataBuf controlDataBuf; // 开关指令数据帧, 复用
protected BindDataBuf bindDataBuf; // 参数装订指令数据帧, 复用
protected QueryDataBuf queryDataBuf; // 参数查询指令数据帧, 复用
protected RouteDataBuf routeDataBuf; // 航线装订指令数据帧, 复用
protected static final int FRAME_SIZE = 32; // 如果各型号不一样该字段取消final并在子类中初始化
protected static final byte[] HEAD = new byte[]{(byte) 0xeb, (byte) 0x90};
// 控制指令回报判断, 指令队列目前只允许一个指令,前一个指令回报或过期后才能发送下一个指令
protected LastCommandRecord lastControl;
protected CommandRecord previousControl;
// 装订指令回报判断
protected LastCommandRecord lastBind;
protected CommandRecord previousParamBind;
// 查询指令回报判断
protected LastCommandRecord lastQuery;
protected CommandRecord previousParamQuery;
// 航线装订指令回报判断
protected CommandQueueRecord previousRouteBind;
// 遥测频率较高转发中心指控的时候不在CacClient中进行协议类实例化这里直接创建ByteBuf模板
protected static ByteBuf telemetryBufHeadToCac;
@ -78,6 +81,14 @@ public class HaborClient extends BaseClient {
", uavType=" + uavType.getInfo() +
'}';
}
public String shortInfo() {
return "[sn='" + sn + '\'' +
", uavId='" + uavId + '\'' +
", fkId=" + fkId +
", uavType=" + uavType.getInfo() +
']';
}
public static HaborClient createClient(UavTypeEnum uavType, String haborSn, Channel channel) {
switch (uavType) {
case FP981A:
@ -114,31 +125,51 @@ public class HaborClient extends BaseClient {
/**被移除管理时, 释放相关资源*/
protected void resourceRelease() {
if (commonDataBuf.refCnt() > 0) {
commonDataBuf.release(commonDataBuf.refCnt());
}
if (controlDataBuf.refCnt() > 0) {
controlDataBuf.release(controlDataBuf.refCnt());
}
commonDataBuf.release();
controlDataBuf.release();
if (telemetryBufHeadToCac.refCnt() > 0) {
telemetryBufHeadToCac.release(telemetryBufHeadToCac.refCnt());
}
lastControl.end();
lastBind.end();
lastQuery.end();
previousControl.end();
previousParamBind.end();
previousParamQuery.end();
previousRouteBind.end();
}
/**只通过get读数不改变readerIndex和writerIndex, 也不可更改refCnt*/
public void process(ByteBuf msg) {
// TODO: 2024/9/18: 处理飞控数据
processInjectResponse(msg);
}
/**注入回报帧处理*/
protected void processInjectResponse(ByteBuf msg) {}
/**发送常发帧*/
protected void writeCommonData() {}
/**向飞控发送控制指令*/
public void writeControlCommand(String uavControlUniId, byte controlCommand) {}
public void writeControlCommand(byte commandCode, String uavControlUniId) {}
/**向飞控发送参数装订指令*/
public void writeParamBindCommand(byte commandCode, byte[] commandContent, String controlUniId) {}
/**向飞控发送参数查询指令*/
public void writeParamQueryCommand(byte commandCode, byte[] commandContent, String controlUniId) {}
/**向飞控发送航线装订指令*/
public void writeRouteBindCommand(byte commandCode, List<byte[]> routeInfoList, String controlUniId) {}
/**设置当前发送数据*/
protected void setCurrentSendData(DataByteBuf dataByteBuf) {
dataByteBuf.resetSendCount();
dataBufToSend = dataByteBuf;
}
/**恢复常发帧数据*/
protected void switchToCommonData() {
setCurrentSendData(commonDataBuf);
dataBufToSend.resetSendCount();
log.info("[cac] {} 设置当前发送数据为常发数据帧", shortInfo());
}
// 启动定时任务常发数据帧
protected void startSendCommonData() {
int period = 1000 / commonDataFreq; // 每帧间隔ms
@ -146,10 +177,10 @@ public class HaborClient extends BaseClient {
this::writeCommonData, 0, period, TimeUnit.MILLISECONDS);
// 检查任务是否成功启动
if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
log.info("[cac] 开始向哈勃终端({})发送常发帧", sn);
log.info("[cac] 开始向哈勃终端({})发送常发帧", shortInfo());
needToSendCommonData.compareAndSet(false, true);
} else {
log.info("[cac] 哈勃终端({})发送常发帧启动失败", sn);
log.info("[cac] 哈勃终端({})发送常发帧启动失败", shortInfo());
}
}
@ -158,7 +189,7 @@ public class HaborClient extends BaseClient {
if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
scheduledFuture.cancel(true); // 取消任务并尝试中断
needToSendCommonData.compareAndSet(true, false);
log.info("[cac] 停止向哈勃终端({})发送常发帧", sn);
log.info("[cac] 停止向哈勃终端({})发送常发帧", shortInfo());
}
}
@ -168,14 +199,14 @@ public class HaborClient extends BaseClient {
/**暂停发送常发帧*/
protected void pauseSendCommonData() {
needToSendCommonData.set(false);
log.info("[cac] 暂停向哈勃终端({})发送常发帧", sn);
// needToSendCommonData.set(false);
log.info("[cac] 暂停向哈勃终端({})发送常发帧", shortInfo());
}
/**恢复发送常发帧*/
protected void resumeSendCommonData() {
needToSendCommonData.set(true);
log.info("[cac] 恢复向哈勃终端({})发送常发帧", sn);
// needToSendCommonData.set(true);
log.info("[cac] 恢复向哈勃终端({})发送常发帧", shortInfo());
}
@ -191,13 +222,6 @@ public class HaborClient extends BaseClient {
CacClient.write(telemetryBufToCac);
}
public void write(ByteBuf buf) {
}
private void buildFrameToCac(ByteBuf srcBuf, ByteBuf dstBuf) {
// TODO: 2024/9/18: 构建飞控数据帧到中心指控
}
/**给数据添加CRC16校验*/
protected void addCRC16(ByteBuf dataBuf) {
ByteBuf slice = dataBuf.slice(2, 28);// 校验第3-30位共28个字节
@ -207,68 +231,52 @@ public class HaborClient extends BaseClient {
/** 记录指令状态,回报指令结果*/
protected class LastCommandRecord {
private byte code; // 指令码
private final ByteBuf lastCommandBuf; // 指令注入内容
private String lastCommandUniId; // 中心指控指令唯一码
// 指令状态
private int status;
public static final int NO_COMMAND = 0; // 空闲
public static final int WATING_RESULT = 1; // 等待回报
// todo 过期时间控制
public LastCommandRecord() {
this.lastCommandBuf = PooledByteBufAllocator.DEFAULT.buffer(16);
/**Cac回报参数具体定义见各型号子类*/
public static abstract class UavTakeOffParamQueryResultParam {
public abstract String toJsonStr() throws IOException;
}
public void recordCommand(byte commandCode, String uniId, ByteBuf commandSlice) {
this.code = commandCode;
this.lastCommandBuf.clear();
this.lastCommandBuf.writeBytes(commandSlice);
this.lastCommandUniId = uniId;
this.status = WATING_RESULT;
protected static class DataByteBuf{
protected ByteBuf buf;
private AtomicInteger sendCount = new AtomicInteger(0);
public DataByteBuf(int frameSize) {buf = PooledByteBufAllocator.DEFAULT.buffer(frameSize);}
public void release() { if (buf.refCnt() > 0) buf.release(buf.refCnt());}
public void resetSendCount() {
sendCount.set(0);
}
public void clearCommand() {
this.lastCommandBuf.clear();
this.lastCommandUniId = null;
this.status = NO_COMMAND;
public int addSendCount() {
return sendCount.incrementAndGet();
}
public int getState() {
return this.status;
public int getSendCount() {
return sendCount.get();
}
public boolean commandMatch(ByteBuf commandSlice) {
return commandSlice.equals(this.lastCommandBuf);
}
/**回报开关指令执行结果,目前仅收到回报时通知*/
public void notifyControlCommandResult() {
Map<String, Object> body = new HashMap<>();
body.put("gcsId", GlobalData.GCS_ID);
body.put("uavId", uavId);
body.put("commandCode", ByteUtils.byteToInt(this.code));
body.put("commandResult", 0);
body.put("commandSource", 1);
body.put("commandUniId", this.lastCommandUniId);
try {
CacHpApi.commandNotify(JSONUtils.obj2json(body));
} catch (IOException e) {
log.error("[cac] 开关指令回报通知失败:{}", body, e);
protected static class CommonDataBuf extends DataByteBuf{
public CommonDataBuf(int frameSize) {
super(frameSize);
}
}
public void notifyParamBindCommandResult() {
protected static class ControlDataBuf extends DataByteBuf{
public int needCount = 10; // 默认帧数
public ControlDataBuf(int frameSize) {
super(frameSize);
}
public void notifyParamQueryCommandResult() {
}
public void end() {
ReferenceCountUtil.release(this.lastCommandBuf);
protected static class BindDataBuf extends DataByteBuf{
public BindDataBuf(int frameSize) {
super(frameSize);
}
}
protected static class QueryDataBuf extends DataByteBuf{
public QueryDataBuf(int frameSize) {
super(frameSize);
}
}
protected static class RouteDataBuf extends DataByteBuf{
public RouteDataBuf(int frameSize) {
super(frameSize);
}
}
}

@ -2,18 +2,24 @@ package com.platform.service.clientmanage;
import com.platform.info.GlobalData;
import com.platform.info.enums.CommandTypeEnum;
import com.platform.info.enums.RemoteFrameEnum;
import com.platform.info.enums.UavTypeEnum;
import com.platform.info.mapping.HaborUavMap;
import com.platform.info.mapping.UavIdMap;
import com.platform.util.ByteUtils;
import com.platform.util.JSONUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.List;
/**
* @Author : shiyi
* @Date : 2024/9/18 10:38
@ -23,53 +29,90 @@ import lombok.extern.slf4j.Slf4j;
public class HaborClient981A extends HaborClient {
private static final byte[] UPPER_DATA_3_4 = new byte[]{0x02, 0x01};
/**常发数据内容*/
private static final byte C0 = 0x00; // 常发数据自定义特征字
private static final byte[] COMMON_DATA_7_30 = new byte[]{
0x00, 0x00, 0x00, // 飞行开关指令7~9, 初始化或无指令3个0x00
0x00, 0x00, 0x00, 0x00, // 飞行连续指令中心指控不管10~13
/**常发数据内容被填入ByteBuf初始内容所有飞机共用, 禁止修改*/
private static final byte C0 = 0x01; // 空白数据自定义特征字
private static final byte[] COMMON_DATA_14_29 = new byte[]{
0x21, C0, C0, C0, C0, // 14~29
C0, C0, C0, C0, C0,
C0, C0, C0, C0, C0, C0,
0x00 // 30
};
/**控制帧数据内容*/
private static final byte C1 = 0x01; // 常发数据自定义特征字
private static final byte[] CONTROL_DATA_7_30 = new byte[]{
0x00, 0x00, 0x00, // 飞行开关指令7~9, 初始化或无指令3个0x00
0x00, 0x00, 0x00, 0x00, // 飞行连续指令中心指控不管10~13
/**控制帧数据内容被填入ByteBuf初始内容*/
private static final byte C1 = 0x02; // 空白数据自定义特征字
private static final byte[] CONTROL_DATA_14_29 = new byte[]{
0x21, C1, C1, C1, C1, // 14~29
C1, C1, C1, C1, C1,
C1, C1, C1, C1, C1, C1,
0x00 // 30
};
// /**装订帧数据内容*/
// private static final byte C2 = 0x03; // 空白数据自定义特征字
// private static final byte[] BIND_DATA_7_30 = new byte[]{
// 0x00, 0x00, 0x00, // 飞行开关指令7~9, 初始化或无指令3个0x00
// 0x00, 0x00, 0x00, 0x00, // 飞行连续指令中心指控不管10~13
// C2, C2, C2, C2, C2, // 14~29, 由中心指控填充
// C2, C2, C2, C2, C2,
// C2, C2, C2, C2, C2, C2,
// 0x00 // 30
// };
//
// /**查询帧数据内容*/
// private static final byte C3 = 0x04; // 空白数据自定义特征字
// private static final byte[] QUERY_DATA_7_30 = new byte[]{
// 0x00, 0x00, 0x00, // 飞行开关指令7~9, 初始化或无指令3个0x00
// 0x00, 0x00, 0x00, 0x00, // 飞行连续指令中心指控不管10~13
// C2, C2, C2, C2, C2, // 14~29, 由中心指控填充
// C2, C2, C2, C2, C2,
// C2, C2, C2, C2, C2, C2,
// 0x00 // 30
// };
//
// /**航线帧数据内容*/
// private static final byte C4 = 0x05; // 空白数据自定义特征字
// private static final byte[] BIND_DATA_7_30 = new byte[]{
// 0x00, 0x00, 0x00, // 飞行开关指令7~9, 初始化或无指令3个0x00
// 0x00, 0x00, 0x00, 0x00, // 飞行连续指令中心指控不管10~13
// C2, C2, C2, C2, C2, // 14~29, 由中心指控填充
// C2, C2, C2, C2, C2,
// C2, C2, C2, C2, C2, C2,
// 0x00 // 30
// };
/**控制指令帧*/
public HaborClient981A(String haborSn, Channel channel) {
super(haborSn, channel);
uavType = UavTypeEnum.FP981A;
uavId = HaborUavMap.getUavIdByHaborSn(haborSn);
uavType = UavIdMap.getUavType(uavId);
fkId = (byte) UavIdMap.getFkId(uavId);
super.commonDataFreq = 1; // 发送频率, 每秒发送帧数
}
@Override
protected void resourceAllocate() {
// 常发数据帧初始化
commonDataBuf = PooledByteBufAllocator.DEFAULT.buffer(FRAME_SIZE);
commonDataBuf.writeBytes(HaborClient.HEAD);
commonDataBuf.writeBytes(UPPER_DATA_3_4);
commonDataBuf.writeByte(fkId);
commonDataBuf.writeByte(0);
commonDataBuf.writeBytes(COMMON_DATA_7_30);
commonDataBuf = new CommonDataBuf(FRAME_SIZE);
initByteBuf(commonDataBuf);
commonDataBuf.buf.writerIndex(13).writeBytes(COMMON_DATA_14_29); // 写入7-30字节
// 开关指令数据帧初始化
controlDataBuf = PooledByteBufAllocator.DEFAULT.buffer(FRAME_SIZE);
controlDataBuf.writeBytes(HaborClient.HEAD);
controlDataBuf.writeBytes(UPPER_DATA_3_4);
controlDataBuf.writeByte(fkId);
controlDataBuf.writeByte(0);
controlDataBuf.writeBytes(CONTROL_DATA_7_30);
controlDataBuf = new ControlDataBuf(FRAME_SIZE);
initByteBuf(controlDataBuf);
controlDataBuf.buf.writerIndex(13).writeBytes(CONTROL_DATA_14_29);
// 参数装订指令数据帧初始化
bindDataBuf = new BindDataBuf(FRAME_SIZE);
initByteBuf(bindDataBuf);
// 参数查询指令数据帧初始化
queryDataBuf = new QueryDataBuf(FRAME_SIZE);
initByteBuf(queryDataBuf);
// 航线装订指令数据帧初始化
routeDataBuf = new RouteDataBuf(FRAME_SIZE);
initByteBuf(routeDataBuf);
dataBufToSend = commonDataBuf; // note 默认发送常发数据帧
// 中心指控数据帧初始化
cacHeadLength = 5 // 魔术2 + 版本号1 + 序列化算法1 + 帧类型1
@ -91,9 +134,23 @@ public class HaborClient981A extends HaborClient {
telemetryBufHeadToCac.writeShort(0);
telemetryBufHeadToCac.writeInt(FRAME_SIZE);
lastControl = new LastCommandRecord();
lastBind = new LastCommandRecord();
lastQuery = new LastCommandRecord();
previousControl = new CommandRecord(CommandTypeEnum.CONTROL,this,16);
previousParamBind = new CommandRecord(CommandTypeEnum.PARAM_BIND, this, 16);
previousParamQuery = new CommandRecord(CommandTypeEnum.PARAM_QUERY, this, 16);
previousRouteBind = new CommandQueueRecord(CommandTypeEnum.ROUTE_BIND, this, 16);
}
/**初始化发送帧内容*/
private void initByteBuf(DataByteBuf dataByteBuf) {
ByteBuf buf = dataByteBuf.buf;
buf.writerIndex(0);
buf.setZero(0, FRAME_SIZE); // 先全部赋0非0数在下面修改
buf.writeBytes(HaborClient.HEAD);
buf.writeBytes(UPPER_DATA_3_4);
buf.writeByte(fkId);
// 10-13字节 默认为0x00
// 14-29字节 在外部动态赋值
}
@Override
@ -121,37 +178,117 @@ public class HaborClient981A extends HaborClient {
return;
}
commonDataBuf.setByte(5, frameIdx.getAndIncrement()); // 帧序号
addCRC16(commonDataBuf);
channel.writeAndFlush(commonDataBuf.retain());
log.debug("{}-{}发送常发帧: {}", sn, uavType, ByteBufUtil.hexDump(commonDataBuf));
dataBufToSend.buf.setByte(5, frameIdx.getAndIncrement()); // 帧序号
addCRC16(dataBufToSend.buf); // 统一添加CRC校验
channel.writeAndFlush(dataBufToSend.buf.retain());
dataBufToSend.addSendCount();
if (dataBufToSend instanceof CommonDataBuf) {
log.debug("[cac] {} 发送常发帧: {}", shortInfo(), ByteBufUtil.hexDump(dataBufToSend.buf));
}
if (dataBufToSend instanceof ControlDataBuf) {
log.info("[cac] {} 发送控制指令: {}", shortInfo(), ByteBufUtil.hexDump(dataBufToSend.buf));
if (dataBufToSend.getSendCount() >= ((ControlDataBuf) dataBufToSend).needCount) {
log.info("[cac] {} 控制指令发送完毕", shortInfo());
switchToCommonData();
}
}
if (dataBufToSend instanceof QueryDataBuf) {
log.info("[cac] {} 发送查询指令: {}", shortInfo(), ByteBufUtil.hexDump(dataBufToSend.buf));
}
/**下发控制指令*/
if (dataBufToSend instanceof BindDataBuf) {
log.info("[cac] {} 发送参数装订指令: {}", shortInfo(), ByteBufUtil.hexDump(dataBufToSend.buf));
}
if (dataBufToSend instanceof RouteDataBuf) {
log.info("[cac] {} 发送航线装订指令: {}", shortInfo(), ByteBufUtil.hexDump(dataBufToSend.buf));
}
}
/**
*
* @param commandCode 14
* @param controlUniId
* */
@Override
public void writeControlCommand(String controlUniId, byte controlCommand) {
pauseSendCommonData();
public void writeControlCommand(byte commandCode, String controlUniId) {
controlDataBuf.buf.setByte(6, commandCode); // 控制指令
controlDataBuf.buf.setByte(7, commandCode); // 控制指令
controlDataBuf.buf.setByte(8, commandCode); // 控制指令
controlDataBuf.needCount = commandNumber(commandCode); // 设置需要发送的次数
setCurrentSendData(controlDataBuf); // 设置当前发送的数据类型
previousControl.recordCommand(commandCode, controlUniId, controlDataBuf.buf.slice(13,16)); // 记录控制指令
// for (int i = 0; i < commandNumber(commandCode); i++) {
// controlDataBuf.setByte(5, frameIdx.getAndIncrement()); // 帧序号
// channel.writeAndFlush(controlDataBuf.retain());
// log.debug("{}-{}发送控制指令帧({}): {}", sn, uavType, ByteUtils.byteToHex(commandCode), ByteBufUtil.hexDump(controlDataBuf));
// }
// previousControl.recordCommand(commandCode, controlUniId, controlDataBuf.slice(13,16)); // 记录控制指令
try {
controlDataBuf.setByte(6, controlCommand); // 控制指令
controlDataBuf.setByte(7, controlCommand); // 控制指令
controlDataBuf.setByte(8, controlCommand); // 控制指令
addCRC16(controlDataBuf);
for (int i = 0; i < commandNumber(controlCommand); i++) {
controlDataBuf.setByte(5, frameIdx.getAndIncrement()); // 帧序号
channel.writeAndFlush(controlDataBuf.retain());
log.debug("{}-{}发送控制指令帧({}): {}", sn, uavType, ByteUtils.byteToHex(controlCommand), ByteBufUtil.hexDump(controlDataBuf));
}
lastControl.recordCommand(controlCommand, controlUniId, controlDataBuf.slice(13,16)); // 记录控制指令
} catch (Exception e) {
log.error("{}-{}发送控制指令帧({})异常: {}", sn, uavType, ByteUtils.byteToHex(controlCommand), e.getMessage());
} finally {
resumeSendCommonData();
}
/**
*
* @param commandCode 14
* @param commandContent 14-29
* @param controlUniId
*/
@Override
public void writeParamBindCommand(byte commandCode, byte[] commandContent, String controlUniId) {
// try {
bindDataBuf.buf.setBytes(13, commandContent);
setCurrentSendData(bindDataBuf); // 设置当前发送的数据类型
previousParamBind.recordCommand(commandCode, controlUniId, bindDataBuf.buf.slice(13,16)); // 记录参数装订指令
// } catch (Exception e) {
// log.error("{}-{}发送参数装订指令帧({})异常: {}", sn, uavType, ByteUtils.byteToHex(commandCode), e.getMessage());
// } finally {
// resumeSendCommonData();
// }
}
/**
*
* @param commandCode 14
* @param commandContent 14-29
* @param controlUniId
*/
@Override
public void writeParamQueryCommand(byte commandCode, byte[] commandContent, String controlUniId) {
queryDataBuf.buf.setBytes(13, commandContent);
setCurrentSendData(queryDataBuf); // 设置当前发送的数据类型
previousParamQuery.recordCommand(commandCode, controlUniId, queryDataBuf.buf.slice(13,16)); // 记录参数查询指令
}
public void process(ByteBuf msg) {
/**
*
* @param commandCode 14
* @param commandContent 14-29
* @param controlUniId
*/
private void writeRouteBindCommand0(byte commandCode, byte[] commandContent, String controlUniId) {
routeDataBuf.buf.setBytes(13, commandContent);
setCurrentSendData(routeDataBuf); // 设置当前发送的数据类型
previousRouteBind.recordCommand(commandCode, controlUniId, routeDataBuf.buf.slice(13,16)); // 记录参数查询指令
}
/**
*
* @param commandCode 14
* @param routeInfoList 14-29
* @param controlUniId
*/
public void writeRouteBindCommand(byte commandCode, List<byte[]> routeInfoList, String controlUniId) {
previousRouteBind.initCommandQueue(routeInfoList);
writeRouteBindCommand0(commandCode, routeInfoList.get(0), controlUniId); //发送第一个节点
}
/**注入回报帧处理*/
@Override
protected void processInjectResponse(ByteBuf msg) {
if (msg.getByte(0) != HEAD[0] && msg.getByte(1) != HEAD[1]) {
return;
}
@ -160,32 +297,122 @@ public class HaborClient981A extends HaborClient {
return;
}
if (LastCommandRecord.WATING_RESULT == lastControl.getState()) {
if (lastControl.commandMatch(msg.slice(13,16))) {
// lastControl.notifyControlCommandResult();
log.info("[cac] 控制指令回报成功");
lastControl.clearCommand();
return;
}
if (checkControlResponse(msg)) return; // 检查控制指令回报
if (checkParamBindResponse(msg)) return; // 检查参数装订回报
if (checkParamQueryResponse(msg)) return; // 检查参数查询回报
if (checkRouteBindResponse(msg)) return; // 检查航线装订回报
}
if (LastCommandRecord.WATING_RESULT == lastBind.getState()) {
if (lastBind.commandMatch(msg.slice(13,16))) {
lastBind.notifyParamBindCommandResult();
lastBind.clearCommand();
return;
/** 检查控制指令回报*/
private boolean checkControlResponse(ByteBuf msg) {
if (CommandRecord.WAITING_RESULT == previousControl.getState()) {
previousControl.addReceiveFrameCount();
if (previousControl.commandMatch(msg.slice(13,16))) {
try {
// previousControl.notifyControlCommandResult();
log.info("[cac] {} 控制指令成功结果回报...", shortInfo());
previousControl.clearCommand();
return true;
} catch (Exception e) {
log.warn("[cac] {} 控制指令回报处理异常:{}",shortInfo(), e.getMessage());
} finally {
switchToCommonData(); // 恢复常发数据帧
}
}
if (LastCommandRecord.WATING_RESULT == lastQuery.getState()) {
if (lastQuery.commandMatch(msg.slice(13,16))) {
lastQuery.notifyParamQueryCommandResult();
lastQuery.clearCommand();
return;
// else {
// if (previousControl.isTimeout()) {
// log.info("[cac] {} 控制指令回报失败, 超时", shortInfo());
// previousControl.clearCommand();
// }
// }
}
return false;
}
/** 检查参数装订回报*/
private boolean checkParamBindResponse(ByteBuf msg) {
if (CommandRecord.WAITING_RESULT == previousParamBind.getState()) {
previousParamBind.addReceiveFrameCount();
if (previousParamBind.commandMatch(msg.slice(13,16))) {
try {
// previousParamBind.notifyParamBindCommandResult(true);
log.info("[cac] {} 指令装订成功结果回报...", shortInfo());
previousParamBind.clearCommand();
return true;
} catch (Exception e) {
log.warn("[cac] {} 指令装订结果回报处理异常:{}",shortInfo(), e.getMessage());
} finally {
switchToCommonData(); // 恢复常发数据帧
}
}
// else {
// if (previousParamBind.isTimeout()) {
// log.info("[cac] {} 指令装订失败, 超过最大帧数仍未回报", shortInfo());
// previousParamBind.clearCommand();
// }
// }
}
return false;
}
/**检查参数查询回报*/
private boolean checkParamQueryResponse(ByteBuf msg) {
if (CommandRecord.WAITING_RESULT == previousParamQuery.getState()) {
previousParamQuery.addReceiveFrameCount();
if (previousParamQuery.commandMatch(msg.slice(13,16))) {
try {
UavTakeOffParamQueryResultParam981A uavTakeOffParamQueryResultParam = new UavTakeOffParamQueryResultParam981A(msg.slice(13,16));
// previousParamQuery.notifyParamQueryCommandResult(true, uavTakeOffParamQueryResultParam);
log.info("[cac] {} 指令查询成功结果回报...", shortInfo());
previousParamQuery.clearCommand();
return true;
} catch (Exception e) {
log.warn("[cac] {} 指令查询结果回报处理异常:{}",shortInfo(), e.getMessage());
} finally {
switchToCommonData(); // 恢复常发数据帧
}
}
// else {
// if (previousControl.isTimeout()) {
// log.info("[cac] {} 指令查询结果回报失败, 超过最大帧数仍未回报", shortInfo());
// previousControl.clearCommand();
// }
// }
}
return false;
}
/**检查航线装订回报*/
private boolean checkRouteBindResponse(ByteBuf msg) {
if (CommandQueueRecord.WAITING_NEXT == previousRouteBind.getState()) {
previousRouteBind.addReceiveFrameCount();
if (previousRouteBind.commandMatch(msg.slice(13, 16))) {
if (previousRouteBind.completeOrWaitNext()) { // 如果指令列表均已回报,则判定成功,向中心指控回报, 并恢复常发帧
try {
// previousRouteBind.notifyParamBindCommandResult(true);
log.info("[cac] {} 航线装订成功结果成功", shortInfo());
previousRouteBind.clearCommand();
return true;
} catch (Exception e) {
log.warn("[cac] {} 航线装订结果回报处理异常:{}", shortInfo(), e.getMessage());
} finally {
switchToCommonData(); // 恢复常发数据帧
}
} else {
// 仍有航点未装订
writeRouteBindCommand0(previousRouteBind.code, previousRouteBind.commandQueue.peek(), previousControl.commandUniId);
log.debug("[cac] {} 当前航点装订成功,剩余航点:{}", shortInfo(), previousRouteBind.commandQueue.size());
}
}
// else {
// if (previousRouteBind.isTimeout()) {
// log.info("[cac] {} 航线装订结果失败, 超过最大帧数仍未回报", shortInfo());
// previousRouteBind.clearCommand();
// }
// }
}
return false;
}
/**开关指令帧数控制*/
private int commandNumber(byte controlCommand) {
switch (controlCommand) {
case (byte) 0xA7: // 解锁
@ -198,4 +425,101 @@ public class HaborClient981A extends HaborClient {
return 5;
}
}
/** 查询指令回报结果参数类, 各型号分开定义*/
@Data
private static class UavTakeOffParamQueryResultParam981A extends UavTakeOffParamQueryResultParam {
/**
* m2; 0.1
*/
private int takeoffAltitude;
/**
* ; 1
*/
private int takeoffThrottle;
/**
* m/s2; 0.1
*/
private int maxFlightSpeed;
/**
* m/s2; 0.1
*/
private int climbSpeedLimit;
/**
* m/s2; 0.1
*/
private int descentSpeedLimit;
/**
* m2; 0.1
*/
private int safeReturnAltitude;
/**
* ,min1; 0.1
*/
private int linkLossLaunchTime;
/**
* m; 1
*/
private int minAscendingAltitude;
/**
* m; 1
*/
private int minDescendingAltitude;
/**
* °2; 0.1
*/
private int runwayHeading;
/**
* m2; 1
*/
private int airDropAltitude;
/**
* 01; 1
*/
private int batteryType;
public UavTakeOffParamQueryResultParam981A(ByteBuf dataBufSlice) {
int idx = 1;
takeoffAltitude = (int) (dataBufSlice.getUnsignedShortLE(idx) * 0.1 * 100);
idx += 2;
takeoffThrottle = dataBufSlice.getUnsignedByte(idx);
idx += 1;
maxFlightSpeed = (int) (dataBufSlice.getUnsignedByte(idx) * 0.1 * 100);
idx += 1;
climbSpeedLimit = (int) (dataBufSlice.getUnsignedByte(idx) * 0.1 * 100);
idx += 1;
descentSpeedLimit = (int) (dataBufSlice.getByte(idx) * 0.1 * 100);
idx += 1;
safeReturnAltitude = (int) (dataBufSlice.getUnsignedShortLE(idx) * 0.1 * 100);
idx += 2;
linkLossLaunchTime = dataBufSlice.getUnsignedByte(idx);
idx += 1;
minAscendingAltitude = dataBufSlice.getUnsignedByte(idx);
idx += 1;
minDescendingAltitude = dataBufSlice.getUnsignedByte(idx);
idx += 1;
runwayHeading = (int) (dataBufSlice.getUnsignedShortLE(idx) * 0.01 * 100);
idx += 2;
airDropAltitude = dataBufSlice.getUnsignedByte(idx);
idx += 1;
batteryType = dataBufSlice.getUnsignedByte(idx);
idx += 1;
}
public String toJsonStr() throws IOException {
return JSONUtils.obj2json(this);
}
}
}

@ -18,7 +18,7 @@ public class CRCUtil {
private static final int INITIAL_VALUE = 0xffff;
/**
* CRC16
* CRC16 使
*
* @param bytes
* @return
@ -234,6 +234,7 @@ public class CRCUtil {
}
/**遥测数据CRC16校验和地面站一致*/
public static byte[] getCRCfromGcsTelemetryData(ByteBuf data, int start, int len) {
byte[] rtn = new byte[2];
short count = 0;
@ -254,6 +255,7 @@ public class CRCUtil {
return rtn;
}
/**遥测数据CRC16校验和地面站一致*/
public static byte[] getCRCfromGcsTelemetryData(byte[] data, int start, int len) {
byte[] rtn = new byte[2];
short count = 0;
@ -320,7 +322,7 @@ public class CRCUtil {
// EB 90 02 01 02 5C 00 00 00 00 00 00 80 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 43 BA
byte[] data = {(byte) 0xEB, (byte) 0x90, (byte) 0x02, (byte) 0x01, (byte) 0x02, (byte) 0x5C, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x21, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
ByteBuf buf = Unpooled.wrappedBuffer(data);
System.out.println("getCRC16WithGcs : " + ByteUtils.bytes2HexString(getCRCfromGcsTelemetryData(data, 2, 28)));
System.out.println("getCRC16WithGcs : " + ByteUtils.bytes2HexString(getCRCfromGcsTelemetryData(buf.slice(2, 28), 0,28)));
System.out.println("getCRCfromGcsTelemetryData : " + ByteUtils.bytes2HexString(getCRCfromGcsTelemetryData(data, 2, 28)));
System.out.println("crc16 : " + ByteUtils.bytes2HexString(crc16(data, 0,28)));
}
}

Loading…
Cancel
Save