package com.ard.work.sdk.fjr.netty;
|
|
import io.netty.buffer.ByteBuf;
|
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.socket.DatagramPacket;
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
import java.net.InetSocketAddress;
|
import java.util.List;
|
|
/**
|
* FJR 协议编码器
|
* 负责将 ThermalCommand 对象转换为符合 FJR 协议的 UDP 数据包
|
*/
|
public class FjrProtocolEncoder extends MessageToMessageEncoder<ThermalCommand> {
|
|
@Override
|
protected void encode(ChannelHandlerContext ctx, ThermalCommand msg, List<Object> out) throws Exception {
|
// 1. 构建原始数据体:地址 + 指令ID + 数据
|
// 注意:cameraId 是业务字段,不包含在协议包中
|
byte[] rawData = new byte[1 + 1 + (msg.getData() != null ? msg.getData().length : 0)];
|
rawData[0] = ThermalCommand.DEVICE_ADDR; // 0x26
|
rawData[1] = msg.getCmdId();
|
if (msg.getData() != null) {
|
System.arraycopy(msg.getData(), 0, rawData, 2, msg.getData().length);
|
}
|
|
// 2. 计算校验和 (基于原始数据)
|
// 规则:所有数据字节相加,取低8位
|
int sum = 0;
|
for (byte b : rawData) {
|
sum += (b & 0xFF);
|
}
|
byte checkSum = (byte) (sum & 0xFF);
|
|
// 3. 数据区转义处理
|
// 规则:
|
// F0 -> F5 00
|
// FF -> F5 0F
|
// F5 -> F5 05
|
ByteBuf escapedBuf = ctx.alloc().buffer();
|
for (byte b : rawData) {
|
if (b == (byte) 0xF0) {
|
escapedBuf.writeByte(0xF5);
|
escapedBuf.writeByte(0x00);
|
} else if (b == (byte) 0xFF) {
|
escapedBuf.writeByte(0xF5);
|
escapedBuf.writeByte(0x0F);
|
} else if (b == (byte) 0xF5) {
|
escapedBuf.writeByte(0xF5);
|
escapedBuf.writeByte(0x05);
|
} else {
|
escapedBuf.writeByte(b);
|
}
|
}
|
|
// 4. 组装最终数据包
|
// 结构:F0(1) + Length(1) + Data(Escaped) + CheckSum(1) + FF(1)
|
ByteBuf packetBuf = ctx.alloc().buffer();
|
packetBuf.writeByte(0xF0); // 起始标志
|
packetBuf.writeByte(rawData.length); // 数据长度 (注意:这里是原始数据的长度,不是转义后的长度)
|
packetBuf.writeBytes(escapedBuf); // 转义后的数据
|
packetBuf.writeByte(checkSum); // 校验和
|
packetBuf.writeByte(0xFF); // 结束标志
|
|
// 释放中间 buffer
|
escapedBuf.release();
|
|
// 5. 包装成 UDP DatagramPacket
|
// 获取当前 Channel 绑定的远程地址
|
InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
|
DatagramPacket packet = new DatagramPacket(packetBuf, remoteAddress);
|
|
out.add(packet);
|
|
// 可选:打印调试日志
|
// System.out.println(">>> 发送指令: " + msg.getCmdId());
|
}
|
}
|