Files
jsowell-charger-web/jsowell-netty/src/main/java/com/jsowell/netty/decoder/ProtocolDnyDecoder.java
2024-07-15 15:07:38 +08:00

118 lines
3.9 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.jsowell.netty.decoder;
import com.jsowell.netty.domain.ProtocolDnyMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;
import java.nio.ByteOrder;
import java.util.List;
@Slf4j
public class ProtocolDnyDecoder extends ByteToMessageDecoder {
private static final int HEADER_LENGTH = 3; // 包头长度
private static final int LENGTH_FIELD_LENGTH = 2; // 长度字段长度
private static final int PHYSICAL_ID_LENGTH = 4; // 物理ID长度
private static final int MESSAGE_ID_LENGTH = 2; // 消息ID长度
private static final int COMMAND_LENGTH = 1; // 命令长度
private static final int CHECKSUM_LENGTH = 2; // 校验字段长度
private static final int MIN_FRAME_LENGTH = HEADER_LENGTH + LENGTH_FIELD_LENGTH + PHYSICAL_ID_LENGTH + MESSAGE_ID_LENGTH + COMMAND_LENGTH + CHECKSUM_LENGTH;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
// 检查是否有足够的数据来读取最小帧长度
if (in.readableBytes() < MIN_FRAME_LENGTH) {
return;
}
// 标记当前读位置
in.markReaderIndex();
// 检查包头
byte[] header = new byte[HEADER_LENGTH];
in.readBytes(header);
if (header[0] != 'D' || header[1] != 'N' || header[2] != 'Y') {
in.resetReaderIndex();
throw new IllegalStateException("Invalid start bytes: " + new String(header));
}
// 读取长度字段
in.order(ByteOrder.LITTLE_ENDIAN); // 确保使用小端模式
int length = in.readUnsignedShort();
if (in.readableBytes() < length) {
in.resetReaderIndex();
return;
}
// 读取物理ID
byte[] physicalId = new byte[PHYSICAL_ID_LENGTH];
in.readBytes(physicalId);
// 读取消息ID
int messageId = in.readUnsignedShort();
// 读取命令
byte command = in.readByte();
// 读取数据
int dataLength = length - (PHYSICAL_ID_LENGTH + MESSAGE_ID_LENGTH + COMMAND_LENGTH + CHECKSUM_LENGTH);
byte[] data = new byte[dataLength];
in.readBytes(data);
// 读取校验字段
int checksum = in.readUnsignedShort();
// 计算校验值并验证
if (!verifyChecksum(header, length, physicalId, messageId, command, data, checksum)) {
in.resetReaderIndex();
throw new IllegalStateException("Invalid checksum");
}
// 创建协议消息对象
ProtocolDnyMessage message = new ProtocolDnyMessage(header, length, physicalId, messageId, command, data, checksum);
// 将解码后的消息添加到输出列表中
out.add(message);
}
// 校验帧校验域的函数
private boolean verifyChecksum(byte[] header, int length, byte[] physicalId, int messageId, byte command, byte[] data, int checksum) {
// 这里需要实现校验逻辑假设我们有一个累加和校验函数sumCheck
int calculatedChecksum = sumCheck(header, length, physicalId, messageId, command, data);
return calculatedChecksum == checksum;
}
// 累加和校验函数,计算从包头到数据的累加和
private int sumCheck(byte[] header, int length, byte[] physicalId, int messageId, byte command, byte[] data) {
int sum = 0;
for (byte b : header) {
sum += b & 0xFF;
}
sum += length & 0xFF;
sum += (length >> 8) & 0xFF;
for (byte b : physicalId) {
sum += b & 0xFF;
}
sum += messageId & 0xFF;
sum += (messageId >> 8) & 0xFF;
sum += command & 0xFF;
for (byte b : data) {
sum += b & 0xFF;
}
return sum & 0xFFFF; // 返回16位结果
}
}