[v0.0.1] 下发指令、常发帧控制

master
shiyi 2 months ago
parent 46bf0a6363
commit 520a79cb98

@ -203,10 +203,12 @@ public class CacHpApi {
return null;
}
public static DirectControlUavParam queryCacDirectControlUav(String body) {
public static DirectControlUavParam queryCacDirectControlUav(String haborSn) {
final String gcsSignApi = HTFP_PATH + "/queryCacDirectControlUav";
Map<String, String> body = new HashMap<>();
body.put("haborSn", haborSn);
try {
Result result = postRequestAndGetResult(gcsSignApi, body);
Result result = postRequestAndGetResult(gcsSignApi, JSONUtils.obj2json(body));
if (result == null || !result.isSuccess()){
log.error("查询单个无人机映射关系失败body={}, result={}", body, result);
return null;

@ -14,7 +14,6 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
* @Author : shiyi
@ -96,7 +95,8 @@ public class GcsService {
if (GlobalData.GCS_SIGNIN) {
return true;
} else {
log.warn("地面站未上线!");
log.warn("地面站未上线!正在重新上线...");
gcsSignInRequest(); // 自动上线
return false;
}
}
@ -143,7 +143,7 @@ public class GcsService {
tcpGcsAuthCacRequest.setReadableDataBytes(null);
if (CacClient.channelIsActive()) {
sendFuture = CacClient.sendMsgToCac(tcpGcsAuthCacRequest).sync();
sendFuture = CacClient.write(tcpGcsAuthCacRequest).sync();
if (sendFuture.isSuccess()){
log.info("[tcpAuth] 认证请求已成功发送发送,认证码:{}", GlobalData.AUTHORIZATION);
return true;

@ -53,7 +53,7 @@ public class RemoteService {
bufToRemote.writeInt(0);
bufToRemote.writeByte(0x00);
// cacClient.channel.writeAndFlush(bufToRemote);
CacClient.sendMsgToCac(bufToRemote);
CacClient.write(bufToRemote);
return true;
} catch (Exception e) {
log.error("运管报文回复失败", e);
@ -65,12 +65,13 @@ public class RemoteService {
*
* @return haborSn
*/
public void queryCacDirectControlUavInfo(String haborSn) {
public DirectControlUavParam queryCacDirectControlUavInfo(String haborSn) {
DirectControlUavParam info = CacHpApi.queryCacDirectControlUav(haborSn);
if (info == null) {
return;
return null;
}
UavIdMap.addMap(UavTypeEnum.getByRemoteCode(info.getUavType()), Integer.parseInt(info.getFlightControlSn()), info.getUavId());
return info;
}
/**
@ -82,9 +83,7 @@ public class RemoteService {
log.debug("查询全量无人机映射关系request body: {}", body);
try {
List<DirectControlUavParam> directControlUavParamList= CacHpApi.queryAllCacDirectControlUavList(body.toString());
if (CollectionUtils.isEmpty(directControlUavParamList)) {
log.error("查询全量无人机映射关系失败");
} else {
if (!CollectionUtils.isEmpty(directControlUavParamList)) {
UavIdMap.clear();
HaborUavMap.clear();
directControlUavParamList.forEach(mapping -> {

@ -107,7 +107,7 @@ public class CacClient {
});
}
public static ChannelFuture sendMsgToCac(Object msg) {
public static ChannelFuture write(Object msg) {
if (channelIsActive()){
return CacClient.channel.writeAndFlush(msg);
}

@ -4,10 +4,11 @@ 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.GcsFrameEnum;
import com.platform.info.enums.RemoteFrameEnum;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import com.platform.info.mapping.HaborUavMap;
import com.platform.service.clientmanage.ClientManager;
import com.platform.service.clientmanage.HaborClient;
import com.platform.util.ByteUtils;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@ -28,29 +29,25 @@ public class CacUavCommandIssuedHandler implements IRemoteMessageHandler {
public void execute(Channel channel, RemoteTcpBaseDataFrame remoteTcpBaseDataFrame) {
if (gcsService.isSignIn()){
CacUavCommandMessage uavCommand = new CacUavCommandMessage(remoteTcpBaseDataFrame);
log.info("对地面站下发指令...{}", uavCommand);
// GcsService.commandUniId = uavCommand.getUavControlUniId();
// log.debug("commandUniId Info: {}", GcsService.commandUniId);
// issuedUavCommandToGcs(uavCommand);
String uavId = uavCommand.getUavId();
String haborSn = HaborUavMap.getHaborSnByUavId(uavId);
if (haborSn == null){
log.error("[cac] 中心指控指令下发失败未找到UavId={}对应的哈勃编号", uavId);
return;
}
byte[] uavCommandCodeId = uavCommand.getUavCommandCodeId();
if (uavCommandCodeId.length!=1) {
log.error("[cac] 中心指控指令下发失败,指令码长度错误:{}", ByteUtils.bytes2HexString(uavCommandCodeId));
return;
}
String uavControlUniId = uavCommand.getUavControlUniId();
log.info("[cac] 中心指控下发指令...{}", uavCommand);
HaborClient client = (HaborClient) ClientManager.getClient(haborSn);
client.writeControlCommand(uavControlUniId, uavCommandCodeId[0]);
} else {
log.warn("无法下发指令");
log.warn("[cac] 当前服务未连接中心指控无法下发指令");
}
}
/**
*
* @param uavCommand
*/
// private void issuedUavCommandToGcs(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.ISSUED_COMMAND.getCode(), bufToGcs);
// }
@Override
public RemoteFrameEnum getFrameType() {
return RemoteFrameEnum.UAV_COMMAND_ISSUED;

@ -4,10 +4,7 @@ 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.GcsFrameEnum;
import com.platform.info.enums.RemoteFrameEnum;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@ -1,60 +0,0 @@
package com.platform.cac.tcp.message.handler;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.cac.tcp.message.dataframe.receive.CacUavControlApplyMessage;
import com.platform.info.enums.GcsFrameEnum;
import com.platform.info.enums.RemoteFrameEnum;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @Author : shiyi
* @Date : 2024/1/9 10:28
* @Description :
*/
@Component @Slf4j
public class CacUavControlApplyHandler implements IRemoteMessageHandler {
// @Resource
// GcsService gcsService;
@Override
public void execute(Channel channel, RemoteTcpBaseDataFrame remoteTcpBaseDataFrame) {
CacUavControlApplyMessage cacUavControlApplyMessage = new CacUavControlApplyMessage(remoteTcpBaseDataFrame);
applyUavControlToGcs(cacUavControlApplyMessage);
}
/**
*
* : {@link com.htfp.gcsplugin.netty.server.messagehandler.handler.GcsUavControlReply}
*
* @param cacUavControlApplyMessage
*/
private void applyUavControlToGcs(CacUavControlApplyMessage cacUavControlApplyMessage) {
// byte reason = (byte) Integer.parseInt(cacUavControlApplyMessage.getUavControlApplyReason());
// String uavId = cacUavControlApplyMessage.getUavId();
// int fkUavId = UavIdMap.getFkId(uavId);
// byte applyGcsId = (byte) Integer.parseInt(cacUavControlApplyMessage.getApplyGcsId());
// String applyId = cacUavControlApplyMessage.getUavControlApplyId();
// GcsService.applyIdToProcess.push(applyGcsId +"-" + uavId, applyId);
// log.info("收到来自地面站 {} 的对无人机 {} 控制请求, 请求原因: {}, applyId: {}", applyGcsId, fkUavId, reason, applyId);
// log.debug("applyId info: {}", GcsService.applyIdToProcess.toString());
//
// // 回复地面站
// ByteBuf bufToGcs = Unpooled.buffer();
// bufToGcs.writeByte(applyGcsId);
// bufToGcs.writeByte((byte) fkUavId);
// bufToGcs.writeByte(reason);
// gcsService.sendToGcs(GcsFrameEnum.CONTROL_FREE.getCode(), bufToGcs);
}
@Override
public RemoteFrameEnum getFrameType() {
return RemoteFrameEnum.UAV_CONTROL_APPLY;
}
}

@ -1,7 +1,6 @@
package com.platform.cac.tcp.message.handler;
import com.platform.cac.GcsService;
import com.platform.cac.RemoteService;
import com.platform.cac.tcp.message.dataframe.RemoteTcpBaseDataFrame;
import com.platform.cac.tcp.message.dataframe.receive.TcpRemoteAuthorization;
@ -24,8 +23,6 @@ public class GcsAuthResponseHandler implements IRemoteMessageHandler {
@Resource
RemoteService remoteService;
@Resource
GcsService gcsService;
@Override
public void execute(Channel channel, RemoteTcpBaseDataFrame remoteTcpBaseDataFrame) {
TcpRemoteAuthorization authResponse = new TcpRemoteAuthorization(remoteTcpBaseDataFrame);

@ -30,10 +30,10 @@ public class HaborUavMap {
return "haboroSn→uavId: " + habor2uavId;
}
public static String getHaborSnByUavId(@NotNull String uavId){
public static String getHaborSnByUavId(@NotNull String uavId) throws NullPointerException{
return uavId2habor.get(uavId);
}
public static String getUavIdByHaborSn(@NotNull String haborSn){
public static String getUavIdByHaborSn(@NotNull String haborSn) throws NullPointerException{
return habor2uavId.get(haborSn);
}

@ -16,7 +16,8 @@ import java.util.concurrent.ConcurrentHashMap;
public class UavIdMap {
// 所有型号uavId到fkId的映射
private static final ConcurrentHashMap<String, Integer> globalMapId = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, Integer> globalMapId = new ConcurrentHashMap<>(); // uavId -> fkId
private static final ConcurrentHashMap<String, UavTypeEnum> uavIdType = new ConcurrentHashMap<>(); // uavId -> uavType
// 各个型号fkId到uavId的映射
private static final ConcurrentHashMap<Integer, String> uavMapId981A = new ConcurrentHashMap<>();
@ -48,6 +49,7 @@ public class UavIdMap {
globalMapId.put(uavId, fkId);
if (uavType != null && uavTypeMapId.containsKey(uavType)) {
uavTypeMapId.get(uavType).put(fkId, uavId);
uavIdType.put(uavId, uavType);
}
}
@ -109,5 +111,11 @@ public class UavIdMap {
}
public static void clear() {
uavTypeMapId.forEach((uavType, uavIdMap) -> uavIdMap.clear());
uavIdType.clear();
}
public static UavTypeEnum getUavType(String uavId) {
return uavIdType.get(uavId);
}
}

@ -25,7 +25,9 @@ public class CacDataRouterHandler extends SimpleChannelInboundHandler<ByteBuf> {
if (client == null || client.getClientType() != ClientTypeEnum.HABOR) {
return;
}
HaborClient haborClient = (HaborClient) client;
haborClient.process(msg);
haborClient.sendToCac(msg);
log.info("数据({}bytes): {}", msg.readableBytes(), ByteBufUtil.hexDump(msg));

@ -3,7 +3,10 @@ package com.platform.service;
import com.platform.cac.RemoteService;
import com.platform.config.ServiceConfig;
import com.platform.info.enums.UavTypeEnum;
import com.platform.info.mapping.HaborUavMap;
import com.platform.info.mapping.UavIdMap;
import com.platform.model.DirectControlUavParam;
import com.platform.service.clientmanage.BaseClient;
import com.platform.service.clientmanage.ClientManager;
import com.platform.service.clientmanage.HaborClient;
@ -251,20 +254,27 @@ public class InMessageHandler extends ChannelInboundHandlerAdapter {
/**接入中心指控系统, 上线*/
private void haborSignIntoCac(String haborSn, Channel channel) {
if (!HaborUavMap.haborIsControllable(haborSn)) {
remoteService.queryCacDirectControlUavInfo(haborSn); // 缓存没查到就向中心指控查一遍,查不到就直接退出
if (!HaborUavMap.haborIsControllable(haborSn)) {
log.info("[cac] 中心指控没有哈勃终端-{}的信息,跳过上线", haborSn);
return;
}
}
if (ClientManager.getClient(channel) != null) {
return;
}
UavTypeEnum uavType = UavTypeEnum.FP981A;
UavIdMap.addMap(uavType, 1, "1");
HaborUavMap.addMap("1", "23293F");
// if (!HaborUavMap.haborIsControllable(haborSn)) {
// DirectControlUavParam info = remoteService.queryCacDirectControlUavInfo(haborSn);// 缓存没查到就向中心指控查一遍,查不到就直接退出
// if (info == null) {
// log.info("[cac] 未查询到哈勃终端-{}的信息,跳过上线", haborSn);
// return;
// }
// }
// if (ClientManager.getClient(channel) != null) {
// // TODO 2025/1/17: 重复上线的如何处理
// return;
// }
// 新建哈勃客户端并加入管理
ClientManager.addAndOnline(new HaborClient(haborSn, channel));
// channel.pipeline().addAfter(); // 上线后添加相关处理器
HaborClient client = HaborClient.createClient(uavType, haborSn, channel);
if (client != null){
ClientManager.addAndOnline(client);
// channel.pipeline().addAfter(); // 上线后添加相关处理器
}
}
/**哈勃下线*/
private void haborSignOutOfCac(Channel channel) {

@ -7,6 +7,7 @@ import io.netty.channel.ChannelFuture;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -83,7 +84,7 @@ public class ClientManager{
/**
* , null
*/
public static BaseClient getClient(String clientSn) throws NullPointerException{
public static BaseClient getClient(@NotNull String clientSn) throws NullPointerException{
return CLIENT_MAP.get(clientSn);
}

@ -1,16 +1,28 @@
package com.platform.service.clientmanage;
import com.google.common.primitives.Bytes;
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.model.DirectControlUavParam;
import com.platform.util.AtomicByte;
import com.platform.util.CRCUtil;
import com.platform.util.JSONUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.util.concurrent.ScheduledFuture;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @Author : shiyi
@ -18,11 +30,27 @@ import javax.annotation.PostConstruct;
* @Description :
*/
@Slf4j @Getter
public class HaborClient extends BaseClient{
public class HaborClient extends BaseClient {
// static HashSet<String> fkSnSet = new HashSet<>();
private UavTypeEnum uavType;
private byte fkId;
private String uavId;
protected UavTypeEnum uavType;
protected byte fkId;
protected String uavId;
// 数据交换控制
protected final AtomicBoolean needToSendCommonData = new AtomicBoolean(false); // 是否发送常发帧
protected int commonDataFreq = 1; // 默认发送频率, 每秒发送帧数, 以各型号子类为准
protected ScheduledFuture scheduledFuture;
// 数据帧内容
protected AtomicByte frameIdx = new AtomicByte(); // 包序号
protected ByteBuf commonDataBuf; // 常发数据帧, 复用
protected ByteBuf controlDataBuf; // 开关指令数据帧, 复用
protected static final int FRAME_SIZE = 32;
protected static final byte[] HEAD = new byte[]{(byte) 0xeb, (byte) 0x90};
public HaborClient(String sn, Channel channel) {
super(sn, channel);
@ -30,40 +58,131 @@ public class HaborClient extends BaseClient{
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
public boolean online() {
return CacHpApi.uavMasterControlNotify(uavId);
boolean online = CacHpApi.uavMasterControlNotify(uavId);
if (online) {
afterOnline();
}
return online;
}
@Override
public boolean offline() {
beforeOffline();
return CacHpApi.uavPowerOff(uavId);
}
// @Override
// public ChannelFuture sendMessage(byte frameType, byte[] data) {
// return channel.writeAndFlush(Unpooled.wrappedBuffer(data));
// }
@Override
public ClientTypeEnum getClientType() {
return ClientTypeEnum.HABOR;
}
/**被管理时初始化*/
protected void afterOnline() {
commonDataBuf = PooledByteBufAllocator.DEFAULT.buffer(FRAME_SIZE); // 常发数据帧
controlDataBuf = PooledByteBufAllocator.DEFAULT.buffer(FRAME_SIZE); // 常发数据帧
}
/**被移除管理时*/
protected void beforeOffline() {
try {
if (commonDataBuf.refCnt() > 0) {
commonDataBuf.release(commonDataBuf.refCnt());
}
if (controlDataBuf.refCnt() > 0) {
controlDataBuf.release(controlDataBuf.refCnt());
}
} catch (Exception e) {
log.info("[cac-haborClient] {}-释放资源失败", sn, e);
}
}
public void process(ByteBuf msg) {
// TODO: 2024/9/18: 处理飞控数据
}
/**发送常发帧*/
protected void writeCommonData() {}
/**向飞控发送控制指令*/
public void writeControlCommand(String uavControlUniId, byte controlCommand) {}
// 启动定时任务常发数据帧
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] 开始向哈勃终端({})发送常发帧", sn);
needToSendCommonData.compareAndSet(false, true);
} else {
log.info("[cac] 哈勃终端({})发送常发帧启动失败", sn);
}
}
// 停止定时任务常发数据帧
protected void stopSendCommonData() {
if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
scheduledFuture.cancel(true); // 取消任务并尝试中断
needToSendCommonData.compareAndSet(true, false);
log.info("[cac] 停止向哈勃终端({})发送常发帧", sn);
}
}
protected boolean isNeedToSendCommonData() {
return needToSendCommonData.get();
}
/**暂停发送常发帧*/
protected void pauseSendCommonData() {
needToSendCommonData.set(false);
log.info("[cac] 暂停向哈勃终端({})发送常发帧", sn);
}
/**恢复发送常发帧*/
protected void resumeSendCommonData() {
needToSendCommonData.set(true);
log.info("[cac] 恢复向哈勃终端({})发送常发帧", sn);
}
/**
*
*
* @param srcBuf ByteBuf
*/
public void sendToCac(ByteBuf srcBuf) {
CacClient.write(srcBuf);
}
public void write(ByteBuf buf) {
}
private void buildFrameToCac(ByteBuf srcBuf, ByteBuf dstBuf) {
// TODO: 2024/9/18: 构建飞控数据帧到中心指控
}
private void queryCacDirectControlUavInfo() {
DirectControlUavParam directControlUavParam = CacHpApi.queryCacDirectControlUav(sn);
/**给数据添加CRC16校验*/
protected void addCRC16(ByteBuf dataBuf) {
ByteBuf slice = dataBuf.slice(2, 28);// 校验第3-30位共28个字节
dataBuf.writerIndex(30);
dataBuf.writeBytes(CRCUtil.getCRCfromGcsTelemetryData(slice, 0, 28));
}
}

@ -0,0 +1,140 @@
package com.platform.service.clientmanage;
import com.platform.info.enums.UavTypeEnum;
import com.platform.util.ByteUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
/**
* @Author : shiyi
* @Date : 2024/9/18 10:38
* @Description : -981A
*/
@Slf4j @Getter
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
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
0x21, C1, C1, C1, C1, // 14~29
C1, C1, C1, C1, C1,
C1, C1, C1, C1, C1, C1,
0x00 // 30
};
/**控制指令帧*/
public HaborClient981A(String sn, Channel channel) {
super(sn, channel);
uavType = UavTypeEnum.FP981A;
// uavId = HaborUavMap.getUavIdByHaborSn(haborSn);
// uavType = UavIdMap.getUavType(uavId);
uavId = "1";
fkId = 2;
super.commonDataFreq = 1; // 发送频率, 每秒发送帧数
}
@Override
protected void afterOnline() {
super.afterOnline();
// 常发数据帧初始化
commonDataBuf.writeBytes(HaborClient.HEAD);
commonDataBuf.writeBytes(UPPER_DATA_3_4);
commonDataBuf.writeByte(fkId);
commonDataBuf.writeByte(0);
commonDataBuf.writeBytes(COMMON_DATA_7_30);
// 开关指令数据帧初始化
controlDataBuf.writeBytes(HaborClient.HEAD);
controlDataBuf.writeBytes(UPPER_DATA_3_4);
controlDataBuf.writeByte(fkId);
controlDataBuf.writeByte(0);
controlDataBuf.writeBytes(CONTROL_DATA_7_30);
}
@Override
public boolean online() {
boolean online = super.online();
if (online) {
startSendCommonData();
}
return online;
}
@Override
public boolean offline() {
boolean offline = super.offline();
if (offline) {
stopSendCommonData();
}
return offline;
}
/**发送常发帧*/
@Override
protected void writeCommonData() {
if (!isNeedToSendCommonData()) {
// 如果当前处于暂停状态,则不发送数据
return;
}
commonDataBuf.setByte(5, frameIdx.getAndIncrement()); // 帧序号
addCRC16(commonDataBuf);
channel.writeAndFlush(commonDataBuf.retain());
log.debug("{}-{}发送常发帧: {}", sn, uavType, ByteBufUtil.hexDump(commonDataBuf));
}
/**下发控制指令*/
@Override
public void writeControlCommand(String controlUniId, byte controlCommand) {
pauseSendCommonData();
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));
}
} catch (Exception e) {
log.error("{}-{}发送控制指令帧({})异常: {}", sn, uavType, ByteUtils.byteToHex(controlCommand), e.getMessage());
} finally {
resumeSendCommonData();
}
}
private int commandNumber(byte controlCommand) {
switch (controlCommand) {
case (byte) 0xA7: // 解锁
return 45;
case (byte) 0xE2: // 一键上锁
return 45;
case (byte) 0xE3: // 开伞
return 45;
default:
return 5;
}
}
}

@ -0,0 +1,41 @@
package com.platform.util;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicByte {
private final AtomicInteger value;
// 构造方法初始化为 0
public AtomicByte() {
value = new AtomicInteger(0);
}
// 获取当前值
public byte get() {
return (byte) value.get(); // 获取并转换为byte类型返回
}
// 获取当前的值并进行自增达到255后归零
public byte getAndIncrement() {
while (true) {
int current = value.get(); // 获取当前值
int next = (current == 255) ? 0 : current + 1; // 自增至255后归零
// 如果当前值等于 current则更新为 next并返回旧值
if (value.compareAndSet(current, next)) {
return (byte) current; // 返回自增前的值
}
}
}
public byte incrementAndGet() {
while (true) {
int current = value.get();
int next = (current == 255) ? 0 : current + 1;
if (value.compareAndSet(current, next)) {
return (byte) next;
}
}
}
}

@ -1,5 +1,8 @@
package com.platform.util;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
public class CRCUtil {
/**
* 8
@ -57,46 +60,267 @@ public class CRCUtil {
return b;
}
private static final int b0 = 0xAA;
private static final int b1 = 0x44;
private static final int b2 = 0x51;
private static final int b3 = 0x15;
private static final int b4 = 0x00;
private static final int b5 = 0x31;
private static final int b6 = 0x30;
private static final int b7 = 0x30;
private static final int b8 = 0x30;
private static final int b9 = 0x31;
private static final int b10 = 0x37;
private static final int b11 = 0x62;
private static final int b12 = 0x64;
private static final int b13 = 0x34;
private static final int b14 = 0x32;
private static final int b15 = 0x65;
private static final int b16 = 0x36;
private static final int b17 = 0x32;
private static final int[] MODBUS_TABLE = generateModbusTable();
private static final int[] CRC16_TABLE = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
private static final int[] CRCLIST= {
0x0,0x0,0x89,0x11,0x12,0x23,0x9b,0x32,0x24,0x46,0xad,0x57,0x36,0x65,0xbf,0x74,
0x48,0x8c,0xc1,0x9d,0x5a,0xaf,0xd3,0xbe,0x6c,0xca,0xe5,0xdb,0x7e,0xe9,0xf7,0xf8,
0x81,0x10,0x8,0x1,0x93,0x33,0x1a,0x22,0xa5,0x56,0x2c,0x47,0xb7,0x75,0x3e,0x64,
0xc9,0x9c,0x40,0x8d,0xdb,0xbf,0x52,0xae,0xed,0xda,0x64,0xcb,0xff,0xf9,0x76,0xe8,
0x2,0x21,0x8b,0x30,0x10,0x2,0x99,0x13,0x26,0x67,0xaf,0x76,0x34,0x44,0xbd,0x55,
0x4a,0xad,0xc3,0xbc,0x58,0x8e,0xd1,0x9f,0x6e,0xeb,0xe7,0xfa,0x7c,0xc8,0xf5,0xd9,
0x83,0x31,0xa,0x20,0x91,0x12,0x18,0x3,0xa7,0x77,0x2e,0x66,0xb5,0x54,0x3c,0x45,
0xcb,0xbd,0x42,0xac,0xd9,0x9e,0x50,0x8f,0xef,0xfb,0x66,0xea,0xfd,0xd8,0x74,0xc9,
0x4,0x42,0x8d,0x53,0x16,0x61,0x9f,0x70,0x20,0x4,0xa9,0x15,0x32,0x27,0xbb,0x36,
0x4c,0xce,0xc5,0xdf,0x5e,0xed,0xd7,0xfc,0x68,0x88,0xe1,0x99,0x7a,0xab,0xf3,0xba,
0x85,0x52,0xc,0x43,0x97,0x71,0x1e,0x60,0xa1,0x14,0x28,0x5,0xb3,0x37,0x3a,0x26,
0xcd,0xde,0x44,0xcf,0xdf,0xfd,0x56,0xec,0xe9,0x98,0x60,0x89,0xfb,0xbb,0x72,0xaa,
0x6,0x63,0x8f,0x72,0x14,0x40,0x9d,0x51,0x22,0x25,0xab,0x34,0x30,0x6,0xb9,0x17,
0x4e,0xef,0xc7,0xfe,0x5c,0xcc,0xd5,0xdd,0x6a,0xa9,0xe3,0xb8,0x78,0x8a,0xf1,0x9b,
0x87,0x73,0xe,0x62,0x95,0x50,0x1c,0x41,0xa3,0x35,0x2a,0x24,0xb1,0x16,0x38,0x7,
0xcf,0xff,0x46,0xee,0xdd,0xdc,0x54,0xcd,0xeb,0xb9,0x62,0xa8,0xf9,0x9a,0x70,0x8b,
0x8,0x84,0x81,0x95,0x1a,0xa7,0x93,0xb6,0x2c,0xc2,0xa5,0xd3,0x3e,0xe1,0xb7,0xf0,
0x40,0x8,0xc9,0x19,0x52,0x2b,0xdb,0x3a,0x64,0x4e,0xed,0x5f,0x76,0x6d,0xff,0x7c,
0x89,0x94,0x0,0x85,0x9b,0xb7,0x12,0xa6,0xad,0xd2,0x24,0xc3,0xbf,0xf1,0x36,0xe0,
0xc1,0x18,0x48,0x9,0xd3,0x3b,0x5a,0x2a,0xe5,0x5e,0x6c,0x4f,0xf7,0x7d,0x7e,0x6c,
0xa,0xa5,0x83,0xb4,0x18,0x86,0x91,0x97,0x2e,0xe3,0xa7,0xf2,0x3c,0xc0,0xb5,0xd1,
0x42,0x29,0xcb,0x38,0x50,0xa,0xd9,0x1b,0x66,0x6f,0xef,0x7e,0x74,0x4c,0xfd,0x5d,
0x8b,0xb5,0x2,0xa4,0x99,0x96,0x10,0x87,0xaf,0xf3,0x26,0xe2,0xbd,0xd0,0x34,0xc1,
0xc3,0x39,0x4a,0x28,0xd1,0x1a,0x58,0xb,0xe7,0x7f,0x6e,0x6e,0xf5,0x5c,0x7c,0x4d,
0xc,0xc6,0x85,0xd7,0x1e,0xe5,0x97,0xf4,0x28,0x80,0xa1,0x91,0x3a,0xa3,0xb3,0xb2,
0x44,0x4a,0xcd,0x5b,0x56,0x69,0xdf,0x78,0x60,0xc,0xe9,0x1d,0x72,0x2f,0xfb,0x3e,
0x8d,0xd6,0x4,0xc7,0x9f,0xf5,0x16,0xe4,0xa9,0x90,0x20,0x81,0xbb,0xb3,0x32,0xa2,
0xc5,0x5a,0x4c,0x4b,0xd7,0x79,0x5e,0x68,0xe1,0x1c,0x68,0xd,0xf3,0x3f,0x7a,0x2e,
0xe,0xe7,0x87,0xf6,0x1c,0xc4,0x95,0xd5,0x2a,0xa1,0xa3,0xb0,0x38,0x82,0xb1,0x93,
0x46,0x6b,0xcf,0x7a,0x54,0x48,0xdd,0x59,0x62,0x2d,0xeb,0x3c,0x70,0xe,0xf9,0x1f,
0x8f,0xf7,0x6,0xe6,0x9d,0xd4,0x14,0xc5,0xab,0xb1,0x22,0xa0,0xb9,0x92,0x30,0x83,
0xc7,0x7b,0x4e,0x6a,0xd5,0x58,0x5c,0x49,0xe3,0x3d,0x6a,0x2c,0xf1,0x1e,0x78,0xf
};
/** <a href="http://www.ip33.com/crc.html">CRC线</a>
* CRC-16 (CCITT)
* polynomial = 0x1021
*
* 0xffff
*/
private static short getCRC16(byte[] bytes, int initialCrc, int xorValue) {
// 初始化 CRC16 余数为 0xffff
int crc = initialCrc;
// 遍历每个字节
for (byte b : bytes) {
// 将字节转换为无符号整数
int bint = b & 0xFF;
// 从查表中取出对应的余数,并与当前的 CRC16 余数进行异或运算
crc = (crc << 8) ^ CRC16_TABLE[(crc >>> 8) ^ bint];
// 将 CRC16 余数限制在 16 位范围内
crc = crc & 0xFFFF;
}
// 将最终的 CRC16 余数与结果异或值进行异或运算
crc = crc ^ xorValue;
return (short) crc;
}
public static byte[] getCRC16CCITTFalse(byte[] bytes){
// 初始化 CRC16 余数为 0xffff
short crc16 = getCRC16(bytes, 0xffff, 0x0000);
return ByteUtils.shortToLittleEndianByteArray(crc16);
}
public static byte[] getCRCXMODEM(byte[] bytes){
// 初始化 CRC16 余数为 0xffff
short crc16 = getCRC16(bytes, 0x0000, 0x0000);
return ByteUtils.shortToLittleEndianByteArray(crc16);
}
/**
* {@link ByteUtils#getCRC(int[])}
* @param bytes
* @return
*/
public static byte[] getCRC16WithGcs(byte[] bytes) {
return getCRCXMODEM(bytes);
}
/**
* byteModbus CRC16
*/
public static byte[] getModbusCRC16(byte[] bytes) {
// modbus的多项式为0x8005, 但是输入输出均需要反转等价使用0xa001多项式 0X8005和0XA001高低位互反
final int polynomial =0xA001;
// 预置16 位CRC寄存器寄存器为十六进制0xFFFF
int crc = 0xFFFF;
for (byte b : bytes) {
// 把第一个 8 位二进制数据 与 16 位的 CRC寄存器的低 8 位相异或, 把结果放于 CRC寄存器
crc = ((crc & 0xFF00) | (crc & 0x00FF) ^ (b & 0xFF));
for (int j = 0; j < Byte.SIZE; j++) {
// 把 CRC 寄存器的内容右移一位( 朝低位)用 0 填补最高位, 并检查右移后的移出位
if ((crc & 0x0001) > 0) {
// 如果移出位为 1, CRC寄存器与多项式A001进行异或
crc = crc >> 1;
crc = crc ^ polynomial;
} else {
// 如果移出位为 0,再次右移一位
crc = crc >> 1;
}
}
}
// 返回 CRC16 校验码, 大端序,高位在前低位在后
return ByteUtils.shortToBigEndianByteArray((short) crc);
}
public static byte[] getModbusCRC16ByteTable(byte[] data) {
// 初始化 CRC16 余数为 0xFFFF
int crc = 0xFFFF;
// 遍历每个字节
for (byte b : data) {
// 将字节转换为无符号整数
int bint = b & 0xFF;
// 从查表中取出对应的余数,并与当前的 CRC16 余数进行异或运算
crc = (crc >>> 8) ^ MODBUS_TABLE[(crc & 0xFF) ^ bint];
}
// 返回 CRC16 校验码, 大端序,高位在前低位在后
return ByteUtils.shortToBigEndianByteArray((short) crc);
}
/** MODBUS CRC16
*/
private static int[] generateModbusTable() {
int[] modbusTable = new int[256];
// 遍历每个可能的 8 位数据
for (int i = 0; i < 256; i++) {
int remainder = i;
for (int bit = 0; bit < 8; bit++) {
// 如果最低位为 1那么余数右移一位并与多项式异或
if ((remainder & 1) == 1) {
remainder = (remainder >>> 1) ^ 0xA001;
} else {
remainder = remainder >>> 1;
}
}
modbusTable[i] = remainder;
}
return modbusTable;
}
public static byte[] getCRCfromGcsTelemetryData(ByteBuf data, int start, int len) {
byte[] rtn = new byte[2];
short count = 0;
int C0 = 0, C1 = 0, Y0 = 0, Y1 = 0, Z0 = 0, Z1 = 0;
while (count < len) {
Y0 = (CRCLIST[2 * (data.getByte(start + count) & 0xFF)] ^ C1) & 0xFF;
Y1 = (CRCLIST[2 * (data.getByte(start + count) & 0xFF) + 1]) & 0xFF;
Z0 = (CRCLIST[2 * C0] & 0xFF);
Z1 = (CRCLIST[2 * C0 + 1] & 0xFF);
C0 = ((Y0 ^ Z0) & 0xFF);
C1 = ((Y1 ^ Z1) & 0xFF);
count++;
}
rtn[1] = (byte) C1;
rtn[0] = (byte) C0;
return rtn;
}
public static byte[] getCRCfromGcsTelemetryData(byte[] data, int start, int len) {
byte[] rtn = new byte[2];
short count = 0;
int C0 = 0, C1 = 0, Y0 = 0, Y1 = 0, Z0 = 0, Z1 = 0;
while (count < len) {
Y0 = (CRCLIST[2 * (data[start + count] & 0xFF)] ^ C1) & 0xFF;
Y1 = (CRCLIST[2 * (data[start + count] & 0xFF) + 1]) & 0xFF;
Z0 = (CRCLIST[2 * C0] & 0xFF);
Z1 = (CRCLIST[2 * C0 + 1] & 0xFF);
C0 = ((Y0 ^ Z0) & 0xFF);
C1 = ((Y1 ^ Z1) & 0xFF);
count++;
}
rtn[1] = (byte) C1;
rtn[0] = (byte) C0;
return rtn;
}
//
// private static final int b0 = 0xAA;
// private static final int b1 = 0x44;
// private static final int b2 = 0x51;
// private static final int b3 = 0x15;
// private static final int b4 = 0x00;
// private static final int b5 = 0x31;
// private static final int b6 = 0x30;
// private static final int b7 = 0x30;
// private static final int b8 = 0x30;
// private static final int b9 = 0x31;
// private static final int b10 = 0x37;
// private static final int b11 = 0x62;
// private static final int b12 = 0x64;
// private static final int b13 = 0x34;
// private static final int b14 = 0x32;
// private static final int b15 = 0x65;
// private static final int b16 = 0x36;
// private static final int b17 = 0x32;
// public static void main(String[] args) {
// byte[] ack = new byte[18];
// ack[0] = (byte)b0;
// ack[1] = (byte)b1;
// ack[2] = (byte)b2;
// ack[3] = (byte)b3;
// ack[4] = (byte)b4;
// ack[5] = (byte)b5;
// ack[6] = (byte)b6;
// ack[7] = (byte)b7;
// ack[8] = (byte)b8;
// ack[9] = (byte)b9;
// ack[10] = (byte)b10;
// ack[11] = (byte)b11;
// ack[12] = (byte)b12;
// ack[13] = (byte)b13;
// ack[14] = (byte)b14;
// ack[15] = (byte)b15;
// ack[16] = (byte)b16;
// ack[17] = (byte)b17;
// byte[] b = crc16(ack, 2, 16);
// StringUtil tool = new StringUtil();
// System.out.println(tool.bytesToHexString(b));
// }
public static void main(String[] args) {
byte[] ack = new byte[18];
ack[0] = (byte)b0;
ack[1] = (byte)b1;
ack[2] = (byte)b2;
ack[3] = (byte)b3;
ack[4] = (byte)b4;
ack[5] = (byte)b5;
ack[6] = (byte)b6;
ack[7] = (byte)b7;
ack[8] = (byte)b8;
ack[9] = (byte)b9;
ack[10] = (byte)b10;
ack[11] = (byte)b11;
ack[12] = (byte)b12;
ack[13] = (byte)b13;
ack[14] = (byte)b14;
ack[15] = (byte)b15;
ack[16] = (byte)b16;
ack[17] = (byte)b17;
byte[] b = crc16(ack, 2, 16);
StringUtil tool = new StringUtil();
System.out.println(tool.bytesToHexString(b));
// 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)));
}
}

@ -2,9 +2,6 @@ server:
port: 11727
service:
port: 11728
app:
debug: false
# 中心指控系统 tcp udp 配置
@ -26,7 +23,7 @@ cac_gcs:
logging:
level:
com.com.platform: debug
com.platform: debug
management:
endpoints:
web:

@ -1,3 +1,6 @@
spring:
profiles:
active: dev
app:
debug: true

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!-- 控制台日志输出-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%highlight(%-5level) %d{HH:mm:ss.SSS} %magenta([%thread]) %cyan(%logger{36}) - %msg%n</pattern>
<!-- <pattern>${log.pattern}</pattern> -->
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--日志文件输出的目录及文件名-->
<FileNamePattern>./log/%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
<MaxFileSize>10MB</MaxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度%msg日志消息%n是换行符-->
<pattern>%highlight(%-5level) %d{HH:mm:ss.SSS} %magenta([%thread]) %cyan(%logger{36}) - %msg%n</pattern>
<pattern>%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="FILE"/>
</root>
<!-- 定义某个包的日志级别 -->
<logger name="com.htfp.gcsplugin" level="debug" additivity="false"> <!-- 添加控制台输出 -->
<appender-ref ref="console"/>
<appender-ref ref="FILE"/>
</logger>
<logger name="io.netty.util.ResourceLeakDetector" level="debug" additivity="false"> <!-- 添加控制台输出 -->
<appender-ref ref="console"/>
<appender-ref ref="FILE"/>
</logger>
</configuration>
Loading…
Cancel
Save