修正物理卡号为BIN码
This commit is contained in:
三丙
2025-10-16 20:15:46 +08:00
parent 8da6d2eaf5
commit 32334b6ba7
14 changed files with 79 additions and 63 deletions

View File

@@ -114,9 +114,41 @@ public class AbstractYunKuaiChongCmdExe {
} }
/** /**
* 编码卡号为BCD格式 * 编码逻辑卡号为BCD格式
* 云快充协议卡号为8字节16位BCD码需要做长度校验和补0操作 * 云快充协议逻辑卡号为8字节16位BCD码需要做长度校验和补0操作
*/ */
protected static byte[] encodeLogicalCardNo(String cardNo) {
if (StringUtils.length(cardNo) > 16) {
throw new IllegalArgumentException("云快充可接受最大逻辑卡号为16位");
}
String cardNoStr = StringUtils.leftPad(cardNo, 16, '0');
return BCDUtil.toBytes(cardNoStr);
}
/**
* 编码物理卡号为8字节long值
* 根据云快充协议文档物理卡号为8字节BIN码直接使用long值
*/
protected static long encodePhysicalCardNo(String cardNo) {
if (StringUtils.isEmpty(cardNo)) {
return 0L;
}
try {
return Long.parseLong(cardNo);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("物理卡号必须是数字: " + cardNo, e);
}
}
/**
* 编码卡号为BCD格式保持向后兼容
* 云快充协议卡号为8字节16位BCD码需要做长度校验和补0操作
* @deprecated 请使用 encodeLogicalCardNo 或 encodePhysicalCardNo 方法
*/
@Deprecated
protected static byte[] encodeCardNo(String cardNo) { protected static byte[] encodeCardNo(String cardNo) {
if (StringUtils.length(cardNo) > 16) { if (StringUtils.length(cardNo) > 16) {
throw new IllegalArgumentException("云快充可接受最大卡号为16位"); throw new IllegalArgumentException("云快充可接受最大卡号为16位");

View File

@@ -44,7 +44,7 @@ public class YunKuaiChongV150OfflineCardBalanceUpdateRequestDLCmd extends YunKua
OfflineCardBalanceUpdateRequest request = message.getMsg().getOfflineCardBalanceUpdateRequest(); OfflineCardBalanceUpdateRequest request = message.getMsg().getOfflineCardBalanceUpdateRequest();
msgBody.writeBytes(encodePileCode(request.getPileCode())); msgBody.writeBytes(encodePileCode(request.getPileCode()));
msgBody.writeBytes(encodeGunCode(request.getGunNo())); msgBody.writeBytes(encodeGunCode(request.getGunNo()));
msgBody.writeBytes(encodeCardNo(request.getCardNo())); msgBody.writeLongLE(encodePhysicalCardNo(request.getCardNo()));
msgBody.writeIntLE(new BigDecimal(request.getLimitYuan()).movePointRight(2).intValue()); msgBody.writeIntLE(new BigDecimal(request.getLimitYuan()).movePointRight(2).intValue());
super.encodeAndWriteFlush(OFFLINE_CARD_BALANCE_UPDATE_REQUEST, msgBody, tcpSession); super.encodeAndWriteFlush(OFFLINE_CARD_BALANCE_UPDATE_REQUEST, msgBody, tcpSession);

View File

@@ -55,12 +55,11 @@ public class YunKuaiChongV150OfflineCardBalanceUpdateResponseULCmd extends YunKu
byteBuf.readBytes(pileCodeBytes); byteBuf.readBytes(pileCodeBytes);
String pileCode = BCDUtil.toString(pileCodeBytes); String pileCode = BCDUtil.toString(pileCodeBytes);
// 物理卡号 // 物理卡号 8字节long值小端序
String cardNo = CharSequenceUtil.EMPTY; String cardNo = CharSequenceUtil.EMPTY;
if(byteBuf.readableBytes() >= 8) { if(byteBuf.readableBytes() >= 8) {
byte[] cardNoBytes = new byte[8]; long physicalCardNoLong = byteBuf.readLongLE();
byteBuf.readBytes(cardNoBytes); cardNo = String.valueOf(physicalCardNoLong);
cardNo = BCDUtil.toString(cardNoBytes);
} }
// 修改结果 0x00-修改成功 0x01-设备编号错误 0x02-卡号错误 // 修改结果 0x00-修改成功 0x01-设备编号错误 0x02-卡号错误

View File

@@ -6,11 +6,6 @@
*/ */
package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; package sanbing.jcpp.protocol.yunkuaichong.v150.cmd;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.OFFLINE_CARD_CLEAR_REQUEST;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V150;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V170;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -21,6 +16,9 @@ import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe; import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage; import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.OFFLINE_CARD_CLEAR_REQUEST;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/** /**
@@ -51,7 +49,7 @@ public class YunKuaiChongV150OfflineCardClearRequestDLCmd extends YunKuaiChongDo
ByteBuf msgBody = Unpooled.buffer(bufferInitialCapacity(request)); ByteBuf msgBody = Unpooled.buffer(bufferInitialCapacity(request));
msgBody.writeBytes(encodePileCode(request.getPileCode())); msgBody.writeBytes(encodePileCode(request.getPileCode()));
msgBody.writeIntLE(request.getTotal()); msgBody.writeIntLE(request.getTotal());
request.getCardNoList().forEach(cardNo -> msgBody.writeBytes(encodeCardNo(cardNo))); request.getCardNoList().forEach(cardNo -> msgBody.writeLongLE(encodePhysicalCardNo(cardNo)));
super.encodeAndWriteFlush(OFFLINE_CARD_CLEAR_REQUEST, msgBody, tcpSession); super.encodeAndWriteFlush(OFFLINE_CARD_CLEAR_REQUEST, msgBody, tcpSession);
} }

View File

@@ -7,15 +7,7 @@
package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; package sanbing.jcpp.protocol.yunkuaichong.v150.cmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V150;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V170;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -27,6 +19,11 @@ import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe; import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage; import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import java.util.List;
import java.util.Map;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/** /**
* 云快充1.5.0 离线卡数据清除应答 * 云快充1.5.0 离线卡数据清除应答
* *
@@ -59,10 +56,9 @@ public class YunKuaiChongV150OfflineCardClearResponseULCmd extends YunKuaiChongU
// 清除结果集合 // 清除结果集合
List<UplinkProto.ClearResult> clearResultList = Lists.newArrayList(); List<UplinkProto.ClearResult> clearResultList = Lists.newArrayList();
while (byteBuf.readableBytes() >= 10) { while (byteBuf.readableBytes() >= 10) {
byte[] cardNoBytes = new byte[8]; // 离线卡物理卡号 8字节long值小端序
// 离线卡物理卡号 long physicalCardNoLong = byteBuf.readLongLE();
byteBuf.readBytes(cardNoBytes); String cardNo = String.valueOf(physicalCardNoLong);
String cardNo = BCDUtil.toString(cardNoBytes);
// 清除标记 0x00 清除失败 0x01 清除成功 // 清除标记 0x00 清除失败 0x01 清除成功
byte clearFlag = byteBuf.readByte(); byte clearFlag = byteBuf.readByte();
// 失败原因 0x01 卡号格式错误 0x02 清除成功 // 失败原因 0x01 卡号格式错误 0x02 清除成功

View File

@@ -6,11 +6,6 @@
*/ */
package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; package sanbing.jcpp.protocol.yunkuaichong.v150.cmd;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.OFFLINE_CARD_QUERY_REQUEST;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V150;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V170;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -21,6 +16,9 @@ import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe; import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage; import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.OFFLINE_CARD_QUERY_REQUEST;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/** /**
* 云快充1.5.0 离线卡数据查询 * 云快充1.5.0 离线卡数据查询
@@ -50,7 +48,7 @@ public class YunKuaiChongV150OfflineCardQueryRequestDLCmd extends YunKuaiChongDo
ByteBuf msgBody = Unpooled.buffer(bufferInitialCapacity(request)); ByteBuf msgBody = Unpooled.buffer(bufferInitialCapacity(request));
msgBody.writeIntLE(request.getTotal()); msgBody.writeIntLE(request.getTotal());
msgBody.writeBytes(encodePileCode(request.getPileCode())); msgBody.writeBytes(encodePileCode(request.getPileCode()));
request.getCardNoList().forEach(cardNo -> msgBody.writeBytes(encodeCardNo(cardNo))); request.getCardNoList().forEach(cardNo -> msgBody.writeLongLE(encodePhysicalCardNo(cardNo)));
super.encodeAndWriteFlush(OFFLINE_CARD_QUERY_REQUEST, msgBody, tcpSession); super.encodeAndWriteFlush(OFFLINE_CARD_QUERY_REQUEST, msgBody, tcpSession);
} }

View File

@@ -7,14 +7,7 @@
package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; package sanbing.jcpp.protocol.yunkuaichong.v150.cmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V150;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V170;
import java.util.List;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -26,6 +19,10 @@ import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe; import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage; import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import java.util.List;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/** /**
* 云快充1.5.0 离线卡数据查询应答 * 云快充1.5.0 离线卡数据查询应答
@@ -50,10 +47,9 @@ public class YunKuaiChongV150OfflineCardQueryResponseULCmd extends YunKuaiChongU
// 清除结果集合 // 清除结果集合
List<UplinkProto.QueryResult> queryResultList = Lists.newArrayList(); List<UplinkProto.QueryResult> queryResultList = Lists.newArrayList();
while (byteBuf.readableBytes() >= 9) { while (byteBuf.readableBytes() >= 9) {
byte[] cardNoBytes = new byte[8]; // 离线卡物理卡号 8字节long值小端序
// 离线卡物理卡号 long physicalCardNoLong = byteBuf.readLongLE();
byteBuf.readBytes(cardNoBytes); String cardNo = String.valueOf(physicalCardNoLong);
String cardNo = BCDUtil.toString(cardNoBytes);
// 查询结果 0x00 不存在 0x01 存在 // 查询结果 0x00 不存在 0x01 存在
byte queryResultByte = byteBuf.readByte(); byte queryResultByte = byteBuf.readByte();
// clearResult // clearResult

View File

@@ -49,8 +49,8 @@ public class YunKuaiChongV150OfflineCardSyncRequestDLCmd extends YunKuaiChongDow
msgBody.writeBytes(encodePileCode(request.getPileCode())); msgBody.writeBytes(encodePileCode(request.getPileCode()));
msgBody.writeIntLE(request.getTotal()); msgBody.writeIntLE(request.getTotal());
request.getCardInfoList().forEach(cardInfo -> { request.getCardInfoList().forEach(cardInfo -> {
msgBody.writeBytes(encodeCardNo(cardInfo.getLogicCardNo())); msgBody.writeBytes(encodeLogicalCardNo(cardInfo.getLogicCardNo()));
msgBody.writeBytes(encodeCardNo(cardInfo.getCardNo())); msgBody.writeLongLE(encodePhysicalCardNo(cardInfo.getCardNo()));
}); });
super.encodeAndWriteFlush(OFFLINE_CARD_SYNC_REQUEST, msgBody, tcpSession); super.encodeAndWriteFlush(OFFLINE_CARD_SYNC_REQUEST, msgBody, tcpSession);

View File

@@ -58,9 +58,9 @@ public class YunKuaiChongV150RemoteStartDLCmd extends YunKuaiChongDownlinkCmdExe
// 枪号 // 枪号
msgBody.writeBytes(encodeGunCode(gunCode)); msgBody.writeBytes(encodeGunCode(gunCode));
// 逻辑卡号 BCD码 // 逻辑卡号 BCD码
msgBody.writeBytes(encodeCardNo(logicalCardNo)); msgBody.writeBytes(encodeLogicalCardNo(logicalCardNo));
// 物理卡号 // 物理卡号 8字节long值小端序
msgBody.writeBytes(encodeCardNo(physicalCardNo)); msgBody.writeLongLE(encodePhysicalCardNo(physicalCardNo));
// 账户余额 // 账户余额
msgBody.writeIntLE(new BigDecimal(limitYuan).multiply(new BigDecimal("100")).intValue()); msgBody.writeIntLE(new BigDecimal(limitYuan).multiply(new BigDecimal("100")).intValue());

View File

@@ -61,7 +61,7 @@ public class YunKuaiChongV150StartChargeAckDLCmd extends YunKuaiChongDownlinkCmd
// 枪号 // 枪号
msgBody.writeBytes(encodeGunCode(gunCode)); msgBody.writeBytes(encodeGunCode(gunCode));
// 逻辑卡号 // 逻辑卡号
msgBody.writeBytes(encodeCardNo(logicalCardNo)); msgBody.writeBytes(encodeLogicalCardNo(logicalCardNo));
// 账户余额 // 账户余额
msgBody.writeIntLE(new BigDecimal(limitYuan).multiply(new BigDecimal("100")).intValue()); msgBody.writeIntLE(new BigDecimal(limitYuan).multiply(new BigDecimal("100")).intValue());
// 鉴权成功标志 // 鉴权成功标志

View File

@@ -65,10 +65,9 @@ public class YunKuaiChongV150StartChargeULCmd extends YunKuaiChongUplinkCmdExe {
int needPasswordCode = byteBuf.readUnsignedByte(); int needPasswordCode = byteBuf.readUnsignedByte();
boolean needPassword = YunKuaiChongPasswordRequiredEnum.isPasswordRequired(needPasswordCode); boolean needPassword = YunKuaiChongPasswordRequiredEnum.isPasswordRequired(needPasswordCode);
// 物理卡号 // 物理卡号 8字节long值小端序
byte[] cardNoBytes = new byte[8]; long physicalCardNoLong = byteBuf.readLongLE();
byteBuf.readBytes(cardNoBytes); String cardNo = String.valueOf(physicalCardNoLong);
String cardNo = BCDUtil.toString(cardNoBytes);
// 密码 // 密码
byte[] passwordBytes = new byte[16]; byte[] passwordBytes = new byte[16];

View File

@@ -150,10 +150,9 @@ public class YunKuaiChongV150TransactionRecordULCmd extends YunKuaiChongUplinkCm
byte stopReasonByte = byteBuf.readByte(); byte stopReasonByte = byteBuf.readByte();
String stopReason = mapStopReason(stopReasonByte); String stopReason = mapStopReason(stopReasonByte);
//31 物理卡号 //31 物理卡号 8字节long值小端序
byte[] cardNoBytes = new byte[8]; long physicalCardNoLong = byteBuf.readLongLE();
byteBuf.readBytes(cardNoBytes); String cardNo = String.valueOf(physicalCardNoLong);
String cardNo = BCDUtil.toString(cardNoBytes);
additionalInfo.put("物理卡号", cardNo); additionalInfo.put("物理卡号", cardNo);
// 构建峰谷电量明细 // 构建峰谷电量明细

View File

@@ -65,9 +65,9 @@ public class YunKuaiChongV160RemoteParallelStartDLCmd extends YunKuaiChongDownli
// 枪号 // 枪号
msgBody.writeBytes(encodeGunCode(gunCode)); msgBody.writeBytes(encodeGunCode(gunCode));
// 逻辑卡号 BCD码 // 逻辑卡号 BCD码
msgBody.writeBytes(encodeCardNo(logicalCardNo)); msgBody.writeBytes(encodeLogicalCardNo(logicalCardNo));
// 物理卡号 // 物理卡号 8字节long值小端序
msgBody.writeBytes(encodeCardNo(physicalCardNo)); msgBody.writeLongLE(encodePhysicalCardNo(physicalCardNo));
// 账户余额 // 账户余额
msgBody.writeIntLE(new BigDecimal(limitYuan).intValue()); msgBody.writeIntLE(new BigDecimal(limitYuan).intValue());
// 并充序号 // 并充序号

View File

@@ -174,10 +174,9 @@ public class YunKuaiChongV170TransactionRecordULCmd extends YunKuaiChongUplinkCm
byte stopReasonByte = byteBuf.readByte(); byte stopReasonByte = byteBuf.readByte();
String stopReason = mapStopReason(stopReasonByte); String stopReason = mapStopReason(stopReasonByte);
// 35. 物理卡号 // 35. 物理卡号 8字节long值小端序
byte[] cardNoBytes = new byte[8]; long physicalCardNoLong = byteBuf.readLongLE();
byteBuf.readBytes(cardNoBytes); String cardNo = String.valueOf(physicalCardNoLong);
String cardNo = BCDUtil.toString(cardNoBytes);
additionalInfo.put("物理卡号", cardNo); additionalInfo.put("物理卡号", cardNo);
// 构建峰谷电量明细 // 构建峰谷电量明细