!43 离线卡数据清除(0x46) 离线卡数据清除应答(0x45)

* merge master
* merge master
* Merge branch 'master' into Feat_离线卡数据清除、离线卡数据查询
* merge master
* Merge branch 'master' into Feat_离线卡数据清除、离线卡数据查询
* 离线卡数据清除(0x46) 离线卡数据清除应答(0x45)
* 离线卡数据清除(0x46) 离线卡数据清除应答(0x45)
* 离线卡数据清除(0x46) 离线卡数据清除应答(0x45)
* 离线卡数据清除(0x46) 离线卡数据清除应答(0x45)
This commit is contained in:
八万
2025-09-13 08:40:51 +00:00
committed by 三丙
parent eff49bb3c0
commit 9451d28894
18 changed files with 521 additions and 15 deletions

View File

@@ -323,4 +323,33 @@ public class TestController extends BaseController {
return ResponseEntity.ok("success");
}
@GetMapping("/api/offlineCardClearRequest")
public ResponseEntity<String> offlineCardClearRequest() {
List<String> cardNoList = Lists.newArrayList("1000000000123456", "1000000000123457", "1000000000123458", "1000000000123459", "1000000000123460");
pileProtocolService.offlineCardClearRequest(OfflineCardClearRequest.newBuilder()
.setPileCode("20231212000010")
.setTotal(cardNoList.size())
.addAllCardNo(cardNoList)
.build());
return ResponseEntity.ok("success");
}
@GetMapping("/api/offlineCardQueryRequest")
public ResponseEntity<String> offlineCardQueryRequest() {
List<String> cardNoList = Lists.newArrayList("1000000000123456", "1000000000123457", "1000000000123458", "1000000000123459", "1000000000123460");
pileProtocolService.offlineCardQueryRequest(OfflineCardQueryRequest.newBuilder()
.setPileCode("20231212000010")
.setTotal(cardNoList.size())
.addAllCardNo(cardNoList)
.build());
return ResponseEntity.ok("success");
}
}

View File

@@ -7,12 +7,12 @@
package sanbing.jcpp.app.service;
import sanbing.jcpp.infrastructure.queue.Callback;
import sanbing.jcpp.proto.gen.DownlinkProto;
import sanbing.jcpp.proto.gen.DownlinkProto.OfflineCardBalanceUpdateRequest;
import sanbing.jcpp.proto.gen.DownlinkProto.OfflineCardSyncRequest;
import sanbing.jcpp.proto.gen.DownlinkProto.OtaRequest;
import sanbing.jcpp.proto.gen.DownlinkProto.SetPricingRequest;
import sanbing.jcpp.proto.gen.UplinkProto.UplinkQueueMessage;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@@ -184,6 +184,25 @@ public interface PileProtocolService {
*/
void onTimeSyncResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback);
/**
* 离线卡数据清除
*/
void offlineCardClearRequest(DownlinkProto.OfflineCardClearRequest request);
/**
* 离线卡数据清除应答
*/
void onOfflineCardClearResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback);
/**
* 离线卡数据查询
*/
void offlineCardQueryRequest(DownlinkProto.OfflineCardQueryRequest request);
/**
* 离线卡数据查询应答
*/
void onOfflineCardQueryResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback);
/**
* 充电过程BMS需求与充电机输出
*/

View File

@@ -748,6 +748,57 @@ public class DefaultPileProtocolService implements PileProtocolService {
callback.onSuccess();
}
@Override
public void offlineCardClearRequest(OfflineCardClearRequest request) {
UUID messageId = UUID.randomUUID();
UUID requestId = UUID.randomUUID();
DownlinkRequestMessage.Builder downlinkRequestMessageBuilder = DownlinkRequestMessage.newBuilder()
.setMessageIdMSB(messageId.getMostSignificantBits())
.setMessageIdLSB(messageId.getLeastSignificantBits())
.setPileCode(request.getPileCode())
.setRequestIdMSB(requestId.getMostSignificantBits())
.setRequestIdLSB(requestId.getLeastSignificantBits())
.setDownlinkCmd(DownlinkCmdEnum.OFFLINE_CARD_CLEAR_REQUEST.name())
.setOfflineCardClearRequest(request);
downlinkCallService.sendDownlinkMessage(downlinkRequestMessageBuilder,request.getPileCode());
}
@Override
public void onOfflineCardClearResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback) {
log.info("接收到充电桩离线卡数据清除应答 {}", uplinkQueueMessage);
// TODO 处理相关业务逻辑
callback.onSuccess();
}
@Override
public void offlineCardQueryRequest(OfflineCardQueryRequest request) {
UUID messageId = UUID.randomUUID();
UUID requestId = UUID.randomUUID();
DownlinkRequestMessage.Builder downlinkRequestMessageBuilder = DownlinkRequestMessage.newBuilder()
.setMessageIdMSB(messageId.getMostSignificantBits())
.setMessageIdLSB(messageId.getLeastSignificantBits())
.setPileCode(request.getPileCode())
.setRequestIdMSB(requestId.getMostSignificantBits())
.setRequestIdLSB(requestId.getLeastSignificantBits())
.setDownlinkCmd(DownlinkCmdEnum.OFFLINE_CARD_QUERY_REQUEST.name())
.setOfflineCardQueryRequest(request);
downlinkCallService.sendDownlinkMessage(downlinkRequestMessageBuilder,request.getPileCode());
}
@Override
public void onOfflineCardQueryResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback) {
log.info("接收到充电桩离线卡数据查询应答 {}", uplinkQueueMessage);
// TODO 处理相关业务逻辑
callback.onSuccess();
}
private static Period createPeriod(int sn, LocalTime beginTime, LocalTime endTime, PricingModelFlag flag) {
Period period = new Period();
period.setSn(sn);

View File

@@ -245,6 +245,14 @@ public class ProtocolUplinkConsumerService extends AbstractConsumerService {
pileProtocolService.onTimeSyncResponse(uplinkQueueMsg, callback);
}else if (uplinkQueueMsg.hasOfflineCardClearResponse()) {
pileProtocolService.onOfflineCardClearResponse(uplinkQueueMsg, callback);
}else if (uplinkQueueMsg.hasOfflineCardQueryResponse()) {
pileProtocolService.onOfflineCardQueryResponse(uplinkQueueMsg, callback);
} else if (uplinkQueueMsg.hasBmsDemandChargerOutputProto()) {
pileProtocolService.postBmsDemandChargerOutput(uplinkQueueMsg, callback);

View File

@@ -36,6 +36,8 @@ message DownlinkRequestMessage {
OfflineCardSyncRequest offlineCardSyncRequest = 31;
TimeSyncRequest timeSyncRequest = 32;
StartChargeResponse startChargeResponse = 33;
OfflineCardClearRequest offlineCardClearRequest = 34;
OfflineCardQueryRequest offlineCardQueryRequest = 35;
}
// 下行响应消息
@@ -246,3 +248,15 @@ message TimeSyncRequest {
string pileCode = 1;
string time = 2;
}
message OfflineCardClearRequest {
string pileCode = 1; // 充电桩编码
int32 total = 2; // 清除离线卡的个数
repeated string cardNo = 3; // 物理卡号集合
}
message OfflineCardQueryRequest {
string pileCode = 1; // 充电桩编码
int32 total = 2; // 查询离线卡的个数
repeated string cardNo = 3; // 物理卡号集合
}

View File

@@ -45,6 +45,8 @@ message UplinkQueueMessage {
TimeSyncResponse timeSyncResponse = 42;
BmsDemandChargerOutputProto bmsDemandChargerOutputProto = 43;
StartChargeRequest startChargeRequest = 44;
OfflineCardClearResponse offlineCardClearResponse = 45;
OfflineCardQueryResponse offlineCardQueryResponse = 46;
}
// 会话关闭事件
@@ -339,6 +341,34 @@ message TimeSyncResponse {
string time = 2;
}
message OfflineCardClearResponse {
string pileCode = 1; // 充电桩编码
repeated ClearResult clearResult = 2; // 清除卡号结果集合
}
message ClearResult {
string cardNo = 1; // 物理卡号
bool success = 2;
optional string errorMsg = 3;
}
message OfflineCardQueryResponse {
string pileCode = 1; // 充电桩编码
repeated QueryResult queryResult = 2; // 查询卡号结果集合
}
message QueryResult {
string cardNo = 1; // 物理卡号
bool exist = 2;
}
// BMS需求充电机输出
message BmsDemandChargerOutputProto {
string pileCode = 4;

View File

@@ -15,6 +15,8 @@ import java.util.function.Function;
public class PropertyUtils {
private PropertyUtils() {}
public static Map<String, String> getProps(String properties) {
Map<String, String> configs = new HashMap<>();
if (StringUtils.isNotEmpty(properties)) {

View File

@@ -41,5 +41,9 @@ public enum DownlinkCmdEnum {
OFFLINE_CARD_SYNC_REQUEST,
OFFLINE_CARD_CLEAR_REQUEST,
OFFLINE_CARD_QUERY_REQUEST,
START_CHARGE_ACK
}

View File

@@ -141,3 +141,21 @@
#### 0x55 对时设置应答
`68 12 01 00 00 55 20 23 12 12 00 00 10 E0 2E 0C 0C 15 08 19 AB 37`
#### 0x46 离线卡数据清除
`68 37 03 00 00 46 20 23 12 12 00 00 10 05 00 00 00 10 00 00 00 00 12 34 56 10 00 00 00 00 12 34 57 10 00 00 00 00 12 34 58 10 00 00 00 00 12 34 59 10 00 00 00 00 12 34 60 76 2f`
#### 0x45 离线卡数据清除应答
#### 成功
`68 3d 19 00 00 45 20 23 12 12 00 00 10 10 00 00 00 00 12 34 56 01 02 10 00 00 00 00 12 34 57 01 02 10 00 00 00 00 12 34 58 01 02 10 00 00 00 00 12 34 59 01 02 10 00 00 00 00 12 34 60 01 02 67 ed`
#### 失败
`68 3d 19 00 00 45 20 23 12 12 00 00 10 10 00 00 00 00 12 34 56 00 01 10 00 00 00 00 12 34 57 00 01 10 00 00 00 00 12 34 58 00 01 10 00 00 00 00 12 34 59 00 01 10 00 00 00 00 12 34 60 00 01 70 ec`
#### 0x48 离线卡数据查询
`68 37 02 00 00 48 05 00 00 00 20 23 12 12 00 00 10 10 00 00 00 00 12 34 56 10 00 00 00 00 12 34 57 10 00 00 00 00 12 34 58 10 00 00 00 00 12 34 59 10 00 00 00 00 12 34 60 a9 e1`
#### 0x47 离线卡数据查询应答
#### 成功
`68 38 19 00 00 47 20 23 12 12 00 00 10 10 00 00 00 00 12 34 56 01 10 00 00 00 00 12 34 57 01 10 00 00 00 00 12 34 58 01 10 00 00 00 00 12 34 59 01 10 00 00 00 00 12 34 60 01 9a 7c`
#### 失败
`68 38 19 00 00 47 20 23 12 12 00 00 10 10 00 00 00 00 12 34 56 00 10 00 00 00 00 12 34 57 00 10 00 00 00 00 12 34 58 00 10 00 00 00 00 12 34 59 00 10 00 00 00 00 12 34 60 00 28 95`

View File

@@ -49,6 +49,8 @@ public class AbstractYunKuaiChongCmdExe {
private static final DecimalFormat PRICING_ID_DECIMAL_FORMAT = new DecimalFormat("0000");
protected static final String SUCCESS = "成功";
protected static final String UNKNOWN_MSG = "未知的异常";
@@ -82,7 +84,7 @@ public class AbstractYunKuaiChongCmdExe {
}
protected static byte[] encodePileCode(String pileCode) {
if (StringUtils.length(pileCode) > 32) {
if (StringUtils.length(pileCode) > 14) {
throw new IllegalArgumentException("云快充可接受最大桩编号为14位");
}
@@ -113,14 +115,14 @@ public class AbstractYunKuaiChongCmdExe {
/**
* 编码卡号为BCD格式
* 云快充协议卡号为6字节12位BCD码需要做长度校验和补0操作
* 云快充协议卡号为8字节16位BCD码需要做长度校验和补0操作
*/
protected static byte[] encodeCardNo(String cardNo) {
if (StringUtils.length(cardNo) > 12) {
throw new IllegalArgumentException("云快充可接受最大卡号为12");
if (StringUtils.length(cardNo) > 16) {
throw new IllegalArgumentException("云快充可接受最大卡号为16");
}
String cardNoStr = StringUtils.leftPad(cardNo, 12, '0');
String cardNoStr = StringUtils.leftPad(cardNo, 16, '0');
return BCDUtil.toBytes(cardNoStr);
}

View File

@@ -52,6 +52,10 @@ public class YunKuaiChongDownlinkCmdConverter implements DownlinkCmdConverter {
COMMAND_MAP.put(DownlinkCmdEnum.OFFLINE_CARD_BALANCE_UPDATE_REQUEST, 0x42);
COMMAND_MAP.put(DownlinkCmdEnum.OFFLINE_CARD_SYNC_REQUEST, 0x44);
COMMAND_MAP.put(DownlinkCmdEnum.SYNC_TIME_REQUEST, 0x56);
COMMAND_MAP.put(DownlinkCmdEnum.OFFLINE_CARD_CLEAR_REQUEST, 0x46);
COMMAND_MAP.put(DownlinkCmdEnum.OFFLINE_CARD_QUERY_REQUEST, 0x48);
}
/**

View File

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

View File

@@ -0,0 +1,73 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
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.Unpooled;
import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.proto.gen.DownlinkProto;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
/**
* 云快充1.5.0 离线卡数据清除
*
* @author bawan
*/
@Slf4j
@ProtocolCmd(value = 0x46, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardClearRequestDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage message, ProtocolContext ctx) {
log.info("{} 云快充1.5.0 离线卡数据清除", tcpSession);
if (!message.getMsg().hasOfflineCardClearRequest()) {
log.error("云快充1.5.0 离线卡数据清除消息体为空");
return;
}
DownlinkProto.OfflineCardClearRequest request = message.getMsg().getOfflineCardClearRequest();
if (request.getTotal()>24 || request.getCardNoCount()>24) {
log.error("云快充1.5.0 离线卡数据清除 下发卡个数最大支持: 24个当前: {}个", request.getTotal());
return;
}
// 初始化 buf
ByteBuf msgBody = Unpooled.buffer(bufferInitialCapacity(request));
msgBody.writeBytes(encodePileCode(request.getPileCode()));
msgBody.writeIntLE(request.getTotal());
request.getCardNoList().forEach(cardNo -> msgBody.writeBytes(encodeCardNo(cardNo)));
super.encodeAndWriteFlush(OFFLINE_CARD_CLEAR_REQUEST, msgBody, tcpSession);
}
/**
* 桩编号 BCD 码 7
* 下发卡个数 BIN 码 1 最大 15 个
* ........ ........ ........ ........
* n卡物理卡号 BIN 码 8 离线卡物理卡号
* @param request request
* @return bufferInitialCapacity
*/
private int bufferInitialCapacity(DownlinkProto.OfflineCardClearRequest request) {
return 7 + 1 + (8 * request.getCardNoCount());
}
}

View File

@@ -0,0 +1,105 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
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 io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.UplinkProto;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
/**
* 云快充1.5.0 离线卡数据清除应答
*
* @author bawan
*/
@Slf4j
@ProtocolCmd(value = 0x45, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardClearResponseULCmd extends YunKuaiChongUplinkCmdExe {
private static final Map<Byte, Map<Byte, String>> CLEAR_RESULT;
static {
CLEAR_RESULT = Map.of(
(byte) 0x00,Map.of((byte)0x01,"卡号格式错误"),
(byte) 0x01,Map.of((byte)0x02,SUCCESS)
);
}
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage message, ProtocolContext ctx) {
log.info("{} 云快充1.5.0 离线卡数据清除应答", tcpSession);
ByteBuf byteBuf = Unpooled.wrappedBuffer(message.getMsgBody());
// 桩编号
byte[] pileCodeBytes = new byte[7];
byteBuf.readBytes(pileCodeBytes);
String pileCode = BCDUtil.toString(pileCodeBytes);
// 清除结果集合
List<UplinkProto.ClearResult> clearResultList = Lists.newArrayList();
while (byteBuf.readableBytes() >= 10) {
byte[] cardNoBytes = new byte[8];
// 离线卡物理卡号
byteBuf.readBytes(cardNoBytes);
String cardNo = BCDUtil.toString(cardNoBytes);
// 清除标记 0x00 清除失败 0x01 清除成功
byte clearFlag = byteBuf.readByte();
// 失败原因 0x01 卡号格式错误 0x02 清除成功
byte failureReason = byteBuf.readByte();
// clearResult
UplinkProto.ClearResult clearResult = UplinkProto.ClearResult.newBuilder()
.setCardNo(cardNo)
.setSuccess(clearFlag == 0x01)
.setErrorMsg(errorMsg(clearFlag,failureReason))
.build();
// add
clearResultList.add(clearResult);
}
UplinkProto.UplinkQueueMessage queueMessage = uplinkMessageBuilder(pileCode, tcpSession, message)
.setOfflineCardClearResponse(UplinkProto.OfflineCardClearResponse.newBuilder()
.setPileCode(pileCode)
.addAllClearResult(clearResultList)
.build())
.build();
// 转发到后端
tcpSession.getForwarder().sendMessage(queueMessage);
}
private String errorMsg(byte clearResult, byte failureReason) {
if(clearResult == 0x01) {
return SUCCESS;
}
Map<Byte, String> clearResultMap = CLEAR_RESULT.get(clearResult);
if(null == clearResultMap) {
return UNKNOWN_MSG;
}
return clearResultMap.getOrDefault(failureReason,UNKNOWN_MSG);
}
}

View File

@@ -0,0 +1,72 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
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.Unpooled;
import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.proto.gen.DownlinkProto;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
/**
* 云快充1.5.0 离线卡数据查询
*
* @author bawan
*/
@Slf4j
@ProtocolCmd(value = 0x48, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardQueryRequestDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage message, ProtocolContext ctx) {
log.info("{} 云快充1.5.0 离线卡数据查询", tcpSession);
if (!message.getMsg().hasOfflineCardQueryRequest()) {
log.error("云快充1.5.0 离线卡数据查询消息体为空");
return;
}
DownlinkProto.OfflineCardQueryRequest request = message.getMsg().getOfflineCardQueryRequest();
if (request.getTotal()>26 || request.getCardNoCount()>26) {
log.error("云快充1.5.0 离线卡数据查询 下发卡个数最大支持: 26个当前: {}个", request.getTotal());
return;
}
// 初始化 buf
ByteBuf msgBody = Unpooled.buffer(bufferInitialCapacity(request));
msgBody.writeIntLE(request.getTotal());
msgBody.writeBytes(encodePileCode(request.getPileCode()));
request.getCardNoList().forEach(cardNo -> msgBody.writeBytes(encodeCardNo(cardNo)));
super.encodeAndWriteFlush(OFFLINE_CARD_QUERY_REQUEST, msgBody, tcpSession);
}
/**
* 桩编号 BCD 码 7
* 下发卡个数 BIN 码 1 最大 15 个
* ........ ........ ........ ........
* n卡物理卡号 BIN 码 8 离线卡物理卡号
* @param request request
* @return bufferInitialCapacity
*/
private int bufferInitialCapacity(DownlinkProto.OfflineCardQueryRequest request) {
return 7 + 1 + ( 8 * request.getCardNoCount());
}
}

View File

@@ -0,0 +1,80 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
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 io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.UplinkProto;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
/**
* 云快充1.5.0 离线卡数据查询应答
*
* @author bawan
*/
@Slf4j
@ProtocolCmd(value = 0x47, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardQueryResponseULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage message, ProtocolContext ctx) {
log.info("{} 云快充1.5.0 离线卡数据查询应答", tcpSession);
ByteBuf byteBuf = Unpooled.wrappedBuffer(message.getMsgBody());
// 桩编号
byte[] pileCodeBytes = new byte[7];
byteBuf.readBytes(pileCodeBytes);
String pileCode = BCDUtil.toString(pileCodeBytes);
// 清除结果集合
List<UplinkProto.QueryResult> queryResultList = Lists.newArrayList();
while (byteBuf.readableBytes() >= 9) {
byte[] cardNoBytes = new byte[8];
// 离线卡物理卡号
byteBuf.readBytes(cardNoBytes);
String cardNo = BCDUtil.toString(cardNoBytes);
// 查询结果 0x00 不存在 0x01 存在
byte queryResultByte = byteBuf.readByte();
// clearResult
UplinkProto.QueryResult queryResult = UplinkProto.QueryResult.newBuilder()
.setCardNo(cardNo)
.setExist(queryResultByte == 0x01)
.build();
// add
queryResultList.add(queryResult);
}
UplinkProto.UplinkQueueMessage queueMessage = uplinkMessageBuilder(pileCode, tcpSession, message)
.setOfflineCardQueryResponse(UplinkProto.OfflineCardQueryResponse.newBuilder()
.setPileCode(pileCode)
.addAllQueryResult(queryResultList)
.build())
.build();
// 转发到后端
tcpSession.getForwarder().sendMessage(queueMessage);
}
}

View File

@@ -9,7 +9,6 @@ package sanbing.jcpp.protocol.yunkuaichong.v150.cmd;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.DownlinkProto.OfflineCardSyncRequest;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
@@ -41,7 +40,7 @@ public class YunKuaiChongV150OfflineCardSyncRequestDLCmd extends YunKuaiChongDow
OfflineCardSyncRequest request = message.getMsg().getOfflineCardSyncRequest();
if (request.getTotal() > 15) {
if (request.getTotal()>15 || request.getCardInfoCount()>15) {
log.error("云快充1.5.0 离线卡数据同步 下发卡个数最大支持: 15个当前: {}个", request.getTotal());
return;
}
@@ -50,8 +49,8 @@ public class YunKuaiChongV150OfflineCardSyncRequestDLCmd extends YunKuaiChongDow
msgBody.writeBytes(encodePileCode(request.getPileCode()));
msgBody.writeIntLE(request.getTotal());
request.getCardInfoList().forEach(cardInfo -> {
msgBody.writeBytes(BCDUtil.toBytes(cardInfo.getLogicCardNo()));
msgBody.writeBytes(BCDUtil.toBytes(cardInfo.getCardNo()));
msgBody.writeBytes(encodeCardNo(cardInfo.getLogicCardNo()));
msgBody.writeBytes(encodeCardNo(cardInfo.getCardNo()));
});
super.encodeAndWriteFlush(OFFLINE_CARD_SYNC_REQUEST, msgBody, tcpSession);

View File

@@ -35,10 +35,6 @@ public class YunKuaiChongV150OfflineCardSyncResponseULCmd extends YunKuaiChongUp
private static final Map<Byte, Map<Byte, String>> FAILURE_REASON;
private static final String SUCCESS = "成功";
static {
FAILURE_REASON = Map.of(
(byte) 0x00,Map.of((byte)0x01,"卡号格式错误",(byte)0x02,"储存空间不足"),