mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-06-12 03:09:48 +08:00
update 电单车协议
This commit is contained in:
@@ -0,0 +1,117 @@
|
|||||||
|
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位结果
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -13,6 +13,9 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder {
|
|||||||
private static final int HEADER_LENGTH_DNY = 3; // "DNY" 包头的长度
|
private static final int HEADER_LENGTH_DNY = 3; // "DNY" 包头的长度
|
||||||
private static final int HEADER_LENGTH_68 = 1; // 68 包头的长度
|
private static final int HEADER_LENGTH_68 = 1; // 68 包头的长度
|
||||||
|
|
||||||
|
// 构造函数,初始化起始标志
|
||||||
|
public StartAndLengthFieldFrameDecoder() {}
|
||||||
|
|
||||||
// 起始标志
|
// 起始标志
|
||||||
// private int HEAD_DATA;
|
// private int HEAD_DATA;
|
||||||
|
|
||||||
@@ -88,6 +91,7 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder {
|
|||||||
// 记录包头开始的index
|
// 记录包头开始的index
|
||||||
int beginReader;
|
int beginReader;
|
||||||
|
|
||||||
|
// 循环查找包头
|
||||||
while (true) {
|
while (true) {
|
||||||
if (buffer.readableBytes() < Math.min(HEADER_LENGTH_DNY, HEADER_LENGTH_68)) {
|
if (buffer.readableBytes() < Math.min(HEADER_LENGTH_DNY, HEADER_LENGTH_68)) {
|
||||||
return; // 数据长度不足,等待更多数据
|
return; // 数据长度不足,等待更多数据
|
||||||
@@ -102,9 +106,9 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder {
|
|||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// 读到了协议的开始标志,结束while循环
|
// 判断是否为DNY包头或68包头
|
||||||
if (isStartOfDnyHeader(buffer, beginReader) || isStartOf68Header(buffer, beginReader)) {
|
if (isStartOfDnyHeader(buffer, beginReader) || isStartOf68Header(buffer, beginReader)) {
|
||||||
break;
|
break; // 读到了协议的开始标志,结束while循环
|
||||||
}
|
}
|
||||||
|
|
||||||
// 未读到包头,略过一个字节
|
// 未读到包头,略过一个字节
|
||||||
@@ -138,6 +142,7 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder {
|
|||||||
buffer.resetReaderIndex();
|
buffer.resetReaderIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断是否为DNY包头
|
||||||
private boolean isStartOfDnyHeader(ByteBuf buffer, int beginReader) {
|
private boolean isStartOfDnyHeader(ByteBuf buffer, int beginReader) {
|
||||||
if (buffer.readableBytes() >= HEADER_LENGTH_DNY) {
|
if (buffer.readableBytes() >= HEADER_LENGTH_DNY) {
|
||||||
byte[] headerBytes = new byte[HEADER_LENGTH_DNY];
|
byte[] headerBytes = new byte[HEADER_LENGTH_DNY];
|
||||||
@@ -148,6 +153,7 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断是否为68包头
|
||||||
private boolean isStartOf68Header(ByteBuf buffer, int beginReader) {
|
private boolean isStartOf68Header(ByteBuf buffer, int beginReader) {
|
||||||
if (buffer.readableBytes() >= HEADER_LENGTH_68) {
|
if (buffer.readableBytes() >= HEADER_LENGTH_68) {
|
||||||
return buffer.getUnsignedByte(beginReader) == 0x68;
|
return buffer.getUnsignedByte(beginReader) == 0x68;
|
||||||
@@ -155,14 +161,17 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理68协议消息
|
||||||
private void decode68Message(ByteBuf buffer, List<Object> out, int beginReader) {
|
private void decode68Message(ByteBuf buffer, List<Object> out, int beginReader) {
|
||||||
|
// 检查剩余数据是否足够
|
||||||
if (buffer.readableBytes() < HEADER_LENGTH_68 + 1) {
|
if (buffer.readableBytes() < HEADER_LENGTH_68 + 1) {
|
||||||
buffer.readerIndex(beginReader);
|
buffer.readerIndex(beginReader);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 消息的长度
|
// 获取消息长度
|
||||||
int length = buffer.getUnsignedByte(beginReader + HEADER_LENGTH_68);
|
int length = buffer.getUnsignedByte(beginReader + HEADER_LENGTH_68);
|
||||||
|
// 检查剩余数据是否足够
|
||||||
if (buffer.readableBytes() < HEADER_LENGTH_68 + 1 + length) {
|
if (buffer.readableBytes() < HEADER_LENGTH_68 + 1 + length) {
|
||||||
buffer.readerIndex(beginReader);
|
buffer.readerIndex(beginReader);
|
||||||
return;
|
return;
|
||||||
@@ -174,14 +183,17 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder {
|
|||||||
out.add(frame);
|
out.add(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理DNY协议消息
|
||||||
private void decodeDnyMessage(ByteBuf buffer, List<Object> out, int beginReader) {
|
private void decodeDnyMessage(ByteBuf buffer, List<Object> out, int beginReader) {
|
||||||
|
// 检查剩余数据是否足够
|
||||||
if (buffer.readableBytes() < HEADER_LENGTH_DNY + 1) {
|
if (buffer.readableBytes() < HEADER_LENGTH_DNY + 1) {
|
||||||
buffer.readerIndex(beginReader);
|
buffer.readerIndex(beginReader);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 消息的长度
|
// 获取消息长度
|
||||||
int length = buffer.getUnsignedByte(beginReader + HEADER_LENGTH_DNY);
|
int length = buffer.getUnsignedByte(beginReader + HEADER_LENGTH_DNY);
|
||||||
|
// 检查剩余数据是否足够
|
||||||
if (buffer.readableBytes() < HEADER_LENGTH_DNY + 1 + length) {
|
if (buffer.readableBytes() < HEADER_LENGTH_DNY + 1 + length) {
|
||||||
buffer.readerIndex(beginReader);
|
buffer.readerIndex(beginReader);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.jsowell.netty.domain;
|
||||||
|
|
||||||
|
public class ProtocolDnyMessage {
|
||||||
|
private final byte[] header;
|
||||||
|
private final int length;
|
||||||
|
private final byte[] physicalId;
|
||||||
|
private final int messageId;
|
||||||
|
private final byte command;
|
||||||
|
private final byte[] data;
|
||||||
|
private final int checksum;
|
||||||
|
|
||||||
|
public ProtocolDnyMessage(byte[] header, int length, byte[] physicalId, int messageId, byte command, byte[] data, int checksum) {
|
||||||
|
this.header = header;
|
||||||
|
this.length = length;
|
||||||
|
this.physicalId = physicalId;
|
||||||
|
this.messageId = messageId;
|
||||||
|
this.command = command;
|
||||||
|
this.data = data;
|
||||||
|
this.checksum = checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getHeader() {
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPhysicalId() {
|
||||||
|
return physicalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMessageId() {
|
||||||
|
return messageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChecksum() {
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.jsowell.netty.server.electricbicycles;
|
package com.jsowell.netty.server.electricbicycles;
|
||||||
|
|
||||||
|
import com.jsowell.netty.decoder.ProtocolDnyDecoder;
|
||||||
import com.jsowell.netty.decoder.StartAndLengthFieldFrameDecoder;
|
import com.jsowell.netty.decoder.StartAndLengthFieldFrameDecoder;
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.ChannelPipeline;
|
import io.netty.channel.ChannelPipeline;
|
||||||
@@ -21,7 +22,7 @@ public class ElectricBicyclesServerChannelInitializer extends ChannelInitializer
|
|||||||
protected void initChannel(SocketChannel channel) throws Exception {
|
protected void initChannel(SocketChannel channel) throws Exception {
|
||||||
ChannelPipeline pipeline = channel.pipeline();
|
ChannelPipeline pipeline = channel.pipeline();
|
||||||
// pipeline.addLast("frameDecoder",new CustomDecoder());
|
// pipeline.addLast("frameDecoder",new CustomDecoder());
|
||||||
pipeline.addLast("frameDecoder", new StartAndLengthFieldFrameDecoder());
|
pipeline.addLast("frameDecoder", new ProtocolDnyDecoder());
|
||||||
pipeline.addLast("decoder", new ByteArrayDecoder());
|
pipeline.addLast("decoder", new ByteArrayDecoder());
|
||||||
pipeline.addLast("encoder", new ByteArrayDecoder());
|
pipeline.addLast("encoder", new ByteArrayDecoder());
|
||||||
//读超时时间设置为10s,0表示不监控
|
//读超时时间设置为10s,0表示不监控
|
||||||
|
|||||||
Reference in New Issue
Block a user