mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-06-13 19:59:53 +08:00
优化友电协议兼容逻辑
This commit is contained in:
@@ -118,21 +118,23 @@ public class YouDianProtocolDecoder extends ByteToMessageDecoder {
|
||||
ByteBuf frame = null;
|
||||
try {
|
||||
// 检查剩余数据是否足够
|
||||
if (buffer.readableBytes() < HEADER_LENGTH_DNY + 1) {
|
||||
if (buffer.readableBytes() < HEADER_LENGTH_DNY + 2) {
|
||||
buffer.readerIndex(beginReader);
|
||||
return;
|
||||
}
|
||||
// 获取消息长度
|
||||
int length = buffer.getUnsignedByte(beginReader + HEADER_LENGTH_DNY);
|
||||
// DNY协议长度域为2字节,小端模式。长度不包含包头和长度域本身。
|
||||
int length = buffer.getUnsignedByte(beginReader + HEADER_LENGTH_DNY)
|
||||
| (buffer.getUnsignedByte(beginReader + HEADER_LENGTH_DNY + 1) << 8);
|
||||
// log.info("获取消息长度, length:{}", length);
|
||||
int frameLength = HEADER_LENGTH_DNY + 2 + length;
|
||||
// 检查剩余数据是否足够
|
||||
if (buffer.readableBytes() < HEADER_LENGTH_DNY + 1 + length) {
|
||||
if (buffer.readableBytes() < frameLength) {
|
||||
buffer.readerIndex(beginReader);
|
||||
return;
|
||||
}
|
||||
// 读取 data 数据
|
||||
frame = buffer.retainedSlice(beginReader, HEADER_LENGTH_DNY + length + 2);
|
||||
buffer.readerIndex(beginReader + HEADER_LENGTH_DNY + length + 2);
|
||||
frame = buffer.retainedSlice(beginReader, frameLength);
|
||||
buffer.readerIndex(beginReader + frameLength);
|
||||
out.add(frame);
|
||||
} finally {
|
||||
// if (frame != null) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.jsowell.netty.handler.electricbicycles;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.jsowell.common.YouDianUtils;
|
||||
import com.jsowell.common.constant.Constants;
|
||||
import com.jsowell.common.core.domain.ebike.EBikeDataProtocol;
|
||||
import com.jsowell.common.util.BytesUtil;
|
||||
import com.jsowell.common.util.YKCUtils;
|
||||
import com.jsowell.netty.factory.EBikeOperateFactory;
|
||||
import com.jsowell.pile.domain.ebike.EBikeCommandEnum;
|
||||
@@ -39,12 +41,46 @@ public class RegistrationHandler extends AbstractEBikeHandler {
|
||||
*/
|
||||
@Override
|
||||
public byte[] supplyProcess(EBikeDataProtocol dataProtocol, ChannelHandlerContext ctx) {
|
||||
// 解析字节数组
|
||||
EBikeMessageCmd20 message = new EBikeMessageCmd20(dataProtocol.getBytes());
|
||||
EBikeMessageCmd20 message;
|
||||
try {
|
||||
// 解析字节数组
|
||||
message = new EBikeMessageCmd20(dataProtocol.getBytes());
|
||||
} catch (Exception e) {
|
||||
handleRegistrationParseError(dataProtocol, ctx, e);
|
||||
return getResult(dataProtocol, Constants.zeroByteArray);
|
||||
}
|
||||
|
||||
// 保存时间
|
||||
saveLastTimeAndCheckChannel(message.getPhysicalId() + "", ctx);
|
||||
log.info("设备注册包:{}", JSON.toJSONString(message));
|
||||
pileBasicInfoService.registrationEBikePile(message);
|
||||
try {
|
||||
pileBasicInfoService.registrationEBikePile(message);
|
||||
} catch (Exception e) {
|
||||
log.error("设备注册包自动建档失败, pileSn:{}, portNumber:{}, msg:{}",
|
||||
message.getPhysicalId(), message.getPortNumber(), BytesUtil.binary(dataProtocol.getBytes(), 16), e);
|
||||
}
|
||||
return getResult(dataProtocol, Constants.zeroByteArray);
|
||||
}
|
||||
|
||||
private void handleRegistrationParseError(EBikeDataProtocol dataProtocol, ChannelHandlerContext ctx, Exception e) {
|
||||
String pileSn = null;
|
||||
int portNumber = 0;
|
||||
try {
|
||||
pileSn = YouDianUtils.convertToPhysicalId(dataProtocol.getPhysicalId()) + "";
|
||||
byte[] msgBody = dataProtocol.getMsgBody();
|
||||
if (msgBody != null && msgBody.length >= 3) {
|
||||
portNumber = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(msgBody, 2, 1));
|
||||
}
|
||||
saveLastTimeAndCheckChannel(pileSn, ctx);
|
||||
log.error("设备注册包解析失败, pileSn:{}, portNumber:{}, msg:{}, msgBodyLength:{}",
|
||||
pileSn, portNumber, BytesUtil.binary(dataProtocol.getBytes(), 16),
|
||||
msgBody == null ? 0 : msgBody.length, e);
|
||||
if (portNumber > 0) {
|
||||
pileBasicInfoService.ensureEBikePileRegistered(pileSn, portNumber, "registration_0x20_parse_fallback");
|
||||
}
|
||||
} catch (Exception fallbackException) {
|
||||
log.error("设备注册包解析失败后兜底处理失败, pileSn:{}, portNumber:{}, msg:{}",
|
||||
pileSn, portNumber, BytesUtil.binary(dataProtocol.getBytes(), 16), fallbackException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import java.util.Arrays;
|
||||
@Builder
|
||||
@ToString
|
||||
public class AbsEBikeMessage2 {
|
||||
protected static final int DATA_START_INDEX = 12;
|
||||
|
||||
protected String header; // 包头 (3字节)
|
||||
protected int msgLength; // 长度 (2字节)
|
||||
protected int physicalId; // 物理ID (4字节)
|
||||
@@ -59,7 +61,7 @@ public class AbsEBikeMessage2 {
|
||||
startIndex += length;
|
||||
length = 1;
|
||||
byte[] commandBytes = BytesUtil.copyBytes(messageBytes, startIndex, length);
|
||||
this.command = BytesUtil.bcd2StrLittle(commandBytes);
|
||||
this.command = BytesUtil.printHexBinary(commandBytes);
|
||||
|
||||
// 读取数据, 暂不处理, 交给子类处理
|
||||
// byte[] dataBytes = BytesUtil.copyBytes(messageBytes, startIndex, length);
|
||||
@@ -72,4 +74,26 @@ public class AbsEBikeMessage2 {
|
||||
public byte[] getMessageBytes() {
|
||||
return null;
|
||||
};
|
||||
|
||||
protected int getBodyLength() {
|
||||
return this.msgLength - 9;
|
||||
}
|
||||
|
||||
protected int getDataEndIndex(byte[] messageBytes) {
|
||||
return messageBytes.length - 2;
|
||||
}
|
||||
|
||||
protected boolean hasDataBytes(byte[] messageBytes, int startIndex, int length) {
|
||||
return length >= 0
|
||||
&& startIndex >= DATA_START_INDEX
|
||||
&& startIndex + length <= getDataEndIndex(messageBytes);
|
||||
}
|
||||
|
||||
protected String getExtendedDataHex(byte[] messageBytes, int startIndex) {
|
||||
int extendedLength = getDataEndIndex(messageBytes) - startIndex;
|
||||
if (extendedLength <= 0) {
|
||||
return null;
|
||||
}
|
||||
return BytesUtil.printHexBinary(BytesUtil.copyBytes(messageBytes, startIndex, extendedLength));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class EBikeMessageCmd02 extends AbsEBikeMessage2 {
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
// private String timestamp;
|
||||
private String timestamp;
|
||||
|
||||
/**
|
||||
* 卡号2字节数
|
||||
@@ -51,7 +51,7 @@ public class EBikeMessageCmd02 extends AbsEBikeMessage2 {
|
||||
public EBikeMessageCmd02(byte[] messageBytes) {
|
||||
super(messageBytes);
|
||||
|
||||
int startIndex = 12;
|
||||
int startIndex = DATA_START_INDEX;
|
||||
int length = 4;
|
||||
this.cardId = BytesUtil.bcd2Str(BytesUtil.copyBytes(messageBytes, startIndex, length)) + "";
|
||||
|
||||
@@ -67,15 +67,20 @@ public class EBikeMessageCmd02 extends AbsEBikeMessage2 {
|
||||
length = 2;
|
||||
this.cardBalance = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)) + "";
|
||||
|
||||
// length = 4;
|
||||
// this.timestamp = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
|
||||
|
||||
if (messageBytes.length > startIndex) {
|
||||
startIndex += length;
|
||||
length = 4;
|
||||
if (hasDataBytes(messageBytes, startIndex, length)) {
|
||||
this.timestamp = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)) + "";
|
||||
startIndex += length;
|
||||
length = 1;
|
||||
card2Length = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length));
|
||||
}
|
||||
|
||||
this.card2Code = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)) + "";
|
||||
length = 1;
|
||||
if (hasDataBytes(messageBytes, startIndex, length)) {
|
||||
card2Length = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length));
|
||||
startIndex += length;
|
||||
}
|
||||
if (card2Length > 0 && hasDataBytes(messageBytes, startIndex, card2Length)) {
|
||||
this.card2Code = BytesUtil.printHexBinary(BytesUtil.copyBytes(messageBytes, startIndex, card2Length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ public class EBikeMessageCmd06 extends AbsEBikeMessage2 {
|
||||
/**
|
||||
* 上发指令当时的时间,有时候不准确,该字段属于调试使用,服务器无需关心此字段
|
||||
*/
|
||||
// private String timestamp;
|
||||
private String timestamp;
|
||||
|
||||
/**
|
||||
* 占位时长:(充电柜专用,其他设备忽略此字段)表示充满后占用设备的时长,单位为分钟
|
||||
@@ -108,8 +108,9 @@ public class EBikeMessageCmd06 extends AbsEBikeMessage2 {
|
||||
|
||||
public EBikeMessageCmd06(byte[] messageBytes) {
|
||||
super(messageBytes);
|
||||
int dataEndIndex = getDataEndIndex(messageBytes);
|
||||
|
||||
int startIndex = 12;
|
||||
int startIndex = DATA_START_INDEX;
|
||||
int length = 1;
|
||||
this.connectorCode = YouDianUtils.convertPortNumberToString(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)));
|
||||
|
||||
@@ -160,31 +161,63 @@ public class EBikeMessageCmd06 extends AbsEBikeMessage2 {
|
||||
|
||||
startIndex += length;
|
||||
length = 2;
|
||||
this.peakPower = new BigDecimal(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)))
|
||||
.multiply(new BigDecimal("0.1")).toString();
|
||||
if (hasPeakPower(dataEndIndex - startIndex) && hasBytes(messageBytes, startIndex, length)) {
|
||||
this.peakPower = new BigDecimal(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)))
|
||||
.multiply(new BigDecimal("0.1")).toString();
|
||||
startIndex += length;
|
||||
}
|
||||
|
||||
startIndex += length;
|
||||
length = 2;
|
||||
this.voltage = new BigDecimal(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)))
|
||||
.multiply(new BigDecimal("0.1")).toString();
|
||||
if (hasBytes(messageBytes, startIndex, length)) {
|
||||
this.voltage = new BigDecimal(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)))
|
||||
.multiply(new BigDecimal("0.1")).toString();
|
||||
startIndex += length;
|
||||
}
|
||||
|
||||
startIndex += length;
|
||||
length = 2;
|
||||
this.current = new BigDecimal(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)))
|
||||
.multiply(new BigDecimal("0.001")).toString();
|
||||
if (hasBytes(messageBytes, startIndex, length)) {
|
||||
this.current = new BigDecimal(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)))
|
||||
.multiply(new BigDecimal("0.001")).toString();
|
||||
startIndex += length;
|
||||
}
|
||||
|
||||
startIndex += length;
|
||||
length = 1;
|
||||
this.ambientTemperature = new BigDecimal(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)))
|
||||
.subtract(new BigDecimal("65")).toString();
|
||||
if (hasBytes(messageBytes, startIndex, length)) {
|
||||
this.ambientTemperature = parseTemperature(messageBytes, startIndex, length);
|
||||
startIndex += length;
|
||||
}
|
||||
|
||||
startIndex += length;
|
||||
length = 1;
|
||||
this.portTemperature = new BigDecimal(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)))
|
||||
.subtract(new BigDecimal("65")).toString();
|
||||
if (hasBytes(messageBytes, startIndex, length)) {
|
||||
this.portTemperature = parseTemperature(messageBytes, startIndex, length);
|
||||
startIndex += length;
|
||||
}
|
||||
|
||||
length = 4;
|
||||
if (hasBytes(messageBytes, startIndex, length)) {
|
||||
this.timestamp = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)) + "";
|
||||
startIndex += length;
|
||||
}
|
||||
|
||||
startIndex += length;
|
||||
length = 2;
|
||||
this.occupancyTime = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)) + "";
|
||||
if (hasBytes(messageBytes, startIndex, length)) {
|
||||
this.occupancyTime = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)) + "";
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasBytes(byte[] messageBytes, int startIndex, int length) {
|
||||
return hasDataBytes(messageBytes, startIndex, length);
|
||||
}
|
||||
|
||||
private boolean hasPeakPower(int optionalLength) {
|
||||
return optionalLength == 2 || optionalLength == 8 || optionalLength >= 12;
|
||||
}
|
||||
|
||||
private String parseTemperature(byte[] messageBytes, int startIndex, int length) {
|
||||
int value = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length));
|
||||
if (value == 0) {
|
||||
return "0";
|
||||
}
|
||||
return String.valueOf(value - 65);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import java.math.BigDecimal;
|
||||
@Setter
|
||||
@ToString(callSuper = true)
|
||||
public class EBikeMessageCmd20 extends AbsEBikeMessage2 {
|
||||
private static final BigDecimal VERSION_FACTOR = new BigDecimal("0.01");
|
||||
|
||||
/**
|
||||
* 固件版本,如100则表示V1.00版本
|
||||
*/
|
||||
@@ -42,13 +44,30 @@ public class EBikeMessageCmd20 extends AbsEBikeMessage2 {
|
||||
*/
|
||||
private String powerBoardVersion;
|
||||
|
||||
/**
|
||||
* 设备分时计费功能:0=不支持,1=支持。旧协议无此字段。
|
||||
*/
|
||||
private Integer deviceSeparateBillingSupport;
|
||||
|
||||
/**
|
||||
* TC模式。旧协议无此字段。
|
||||
*/
|
||||
private Integer tcMode;
|
||||
|
||||
/**
|
||||
* 扩展数据:标准注册字段后的原始扩展字段
|
||||
*/
|
||||
private String extendedData;
|
||||
|
||||
public EBikeMessageCmd20(byte[] messageBytes) {
|
||||
super(messageBytes);
|
||||
if (getBodyLength() < 8) {
|
||||
throw new IllegalArgumentException("Invalid command 0x20 body length: " + getBodyLength());
|
||||
}
|
||||
|
||||
int startIndex = 12;
|
||||
int startIndex = DATA_START_INDEX;
|
||||
int length = 2;
|
||||
this.firmwareVersion = new BigDecimal(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)))
|
||||
.multiply(new BigDecimal("0.1")).toString();
|
||||
this.firmwareVersion = parseVersion(messageBytes, startIndex, length);
|
||||
|
||||
startIndex += length;
|
||||
length = 1;
|
||||
@@ -64,10 +83,34 @@ public class EBikeMessageCmd20 extends AbsEBikeMessage2 {
|
||||
|
||||
startIndex += length;
|
||||
length = 1;
|
||||
this.workMode = BytesUtil.bcd2StrLittle(BytesUtil.copyBytes(messageBytes, startIndex, length));
|
||||
this.workMode = BytesUtil.printHexBinary(BytesUtil.copyBytes(messageBytes, startIndex, length));
|
||||
|
||||
startIndex += length;
|
||||
length = 2;
|
||||
this.powerBoardVersion = BytesUtil.bcd2StrLittle(BytesUtil.copyBytes(messageBytes, startIndex, length));
|
||||
this.powerBoardVersion = parseVersion(messageBytes, startIndex, length);
|
||||
|
||||
startIndex += length;
|
||||
int extendedStartIndex = startIndex;
|
||||
length = 1;
|
||||
if (hasBytes(messageBytes, startIndex, length)) {
|
||||
this.deviceSeparateBillingSupport = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length));
|
||||
startIndex += length;
|
||||
}
|
||||
|
||||
length = 1;
|
||||
if (hasBytes(messageBytes, startIndex, length)) {
|
||||
this.tcMode = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length));
|
||||
}
|
||||
|
||||
this.extendedData = getExtendedDataHex(messageBytes, extendedStartIndex);
|
||||
}
|
||||
|
||||
private String parseVersion(byte[] messageBytes, int startIndex, int length) {
|
||||
return new BigDecimal(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)))
|
||||
.multiply(VERSION_FACTOR).toString();
|
||||
}
|
||||
|
||||
private boolean hasBytes(byte[] messageBytes, int startIndex, int length) {
|
||||
return hasDataBytes(messageBytes, startIndex, length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class EBikeMessageCmd21 extends AbsEBikeMessage2 {
|
||||
super(messageBytes);
|
||||
|
||||
// 读取结果
|
||||
int startIndex = 12;
|
||||
int startIndex = DATA_START_INDEX;
|
||||
int length = 2;
|
||||
this.voltage = new BigDecimal(BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)))
|
||||
.multiply(new BigDecimal("0.1")).toString();
|
||||
@@ -78,14 +78,18 @@ public class EBikeMessageCmd21 extends AbsEBikeMessage2 {
|
||||
|
||||
startIndex += length;
|
||||
length = 1;
|
||||
this.rssi = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)) + "";
|
||||
if (hasDataBytes(messageBytes, startIndex, length)) {
|
||||
this.rssi = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length)) + "";
|
||||
}
|
||||
|
||||
startIndex += length;
|
||||
length = 1;
|
||||
int i = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length));
|
||||
if (i > 65) {
|
||||
i = i - 65;
|
||||
if (hasDataBytes(messageBytes, startIndex, length)) {
|
||||
int i = BytesUtil.bytesToIntLittle(BytesUtil.copyBytes(messageBytes, startIndex, length));
|
||||
if (i > 0) {
|
||||
i = i - 65;
|
||||
}
|
||||
this.temperature = i + "";
|
||||
}
|
||||
this.temperature = i + "";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user