From 6a8157e179f7abfe1804005565caebcf57139d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AB=E4=B8=87?= <920444250@qq.com> Date: Mon, 25 Aug 2025 03:05:54 +0000 Subject: [PATCH] =?UTF-8?q?!27=20Merge=20branch=20'master'=20into=20Feat?= =?UTF-8?q?=5F=E8=BF=9C=E7=A8=8B=E8=B4=A6=E6=88=B7=E4=BD=99=E9=A2=9D?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=20*=20=E7=A6=BB=E7=BA=BF=E5=8D=A1=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=90=8C=E6=AD=A5(0x44)=20=E7=A6=BB=E7=BA=BF=E5=8D=A1?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E5=BA=94=E7=AD=94(0x43)=20?= =?UTF-8?q?*=20Merge=20branch=20'master'=20into=20Feat=5F=E8=BF=9C?= =?UTF-8?q?=E7=A8=8B=E8=B4=A6=E6=88=B7=E4=BD=99=E9=A2=9D=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=20*=20=E7=A6=BB=E7=BA=BF=E5=8D=A1=E6=95=B0=E6=8D=AE=E5=90=8C?= =?UTF-8?q?=E6=AD=A5(0x44)=20=E7=A6=BB=E7=BA=BF=E5=8D=A1=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E5=BA=94=E7=AD=94(0x43)=20*=20=E4=B8=8B?= =?UTF-8?q?=E5=8F=91=E5=8D=A1=E4=B8=AA=E6=95=B0=20=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=20*=20Merge=20branch=20'master'=20into=20Fea?= =?UTF-8?q?t=5F=E8=BF=9C=E7=A8=8B=E8=B4=A6=E6=88=B7=E4=BD=99=E9=A2=9D?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=20*=20=E7=A6=BB=E7=BA=BF=E5=8D=A1=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=90=8C=E6=AD=A5(0x44)=20=20=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E5=8D=A1=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E5=BA=94=E7=AD=94?= =?UTF-8?q?(0x43)=20*=20=E8=BF=9C=E7=A8=8B=E8=B4=A6=E6=88=B7=E4=BD=99?= =?UTF-8?q?=E9=A2=9D=E6=9B=B4=E6=96=B0(0x42)=20=20=E4=BD=99=E9=A2=9D?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=BA=94=E7=AD=94(0x41)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jcpp/app/adapter/TestController.java | 51 +++++++++- .../jcpp/app/service/PileProtocolService.java | 19 ++++ .../impl/DefaultPileProtocolService.java | 59 +++++++++++- .../ProtocolUplinkConsumerService.java | 10 +- .../src/main/proto/protocol.proto | 36 ++++++++ .../jcpp/protocol/domain/DownlinkCmdEnum.java | 4 + .../src/main/resources/log4j2.xml | 2 +- jcpp-protocol-yunkuaichong/READMD.md | 19 +++- .../AbstractYunKuaiChongCmdExe.java | 4 + .../enums/YunKuaiChongDownlinkCmdEnum.java | 5 + ...nKuaiChongV150LimitUpdateRequestDLCmd.java | 54 +++++++++++ ...KuaiChongV150LimitUpdateResponseULCmd.java | 78 ++++++++++++++++ ...iChongV150OfflineCardSyncRequestDLCmd.java | 74 +++++++++++++++ ...ChongV150OfflineCardSyncResponseULCmd.java | 92 +++++++++++++++++++ .../cmd/YunKuaiChongV150OtaResponseULCmd.java | 2 +- 15 files changed, 495 insertions(+), 14 deletions(-) create mode 100644 jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LimitUpdateRequestDLCmd.java create mode 100644 jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LimitUpdateResponseULCmd.java create mode 100644 jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OfflineCardSyncRequestDLCmd.java create mode 100644 jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OfflineCardSyncResponseULCmd.java diff --git a/jcpp-app/src/main/java/sanbing/jcpp/app/adapter/TestController.java b/jcpp-app/src/main/java/sanbing/jcpp/app/adapter/TestController.java index 63da233..c50e81d 100644 --- a/jcpp-app/src/main/java/sanbing/jcpp/app/adapter/TestController.java +++ b/jcpp-app/src/main/java/sanbing/jcpp/app/adapter/TestController.java @@ -6,16 +6,28 @@ */ package sanbing.jcpp.app.adapter; -import jakarta.annotation.Resource; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; + import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; + +import com.google.common.collect.Lists; + +import jakarta.annotation.Resource; import sanbing.jcpp.app.service.PileProtocolService; import sanbing.jcpp.proto.gen.ProtocolProto; -import sanbing.jcpp.proto.gen.ProtocolProto.*; - -import java.math.BigDecimal; -import java.util.HashMap; +import sanbing.jcpp.proto.gen.ProtocolProto.CardInfo; +import sanbing.jcpp.proto.gen.ProtocolProto.FlagPriceProto; +import sanbing.jcpp.proto.gen.ProtocolProto.OfflineCardSyncRequest; +import sanbing.jcpp.proto.gen.ProtocolProto.PeriodProto; +import sanbing.jcpp.proto.gen.ProtocolProto.PricingModelFlag; +import sanbing.jcpp.proto.gen.ProtocolProto.PricingModelProto; +import sanbing.jcpp.proto.gen.ProtocolProto.PricingModelRule; +import sanbing.jcpp.proto.gen.ProtocolProto.PricingModelType; +import sanbing.jcpp.proto.gen.ProtocolProto.SetPricingRequest; /** * @author baigod @@ -174,4 +186,33 @@ public class TestController { return ResponseEntity.ok("success"); } + @GetMapping("/api/limitUpdateRequest") + public ResponseEntity limitUpdateRequest() { + + pileProtocolService.limitUpdateRequest(ProtocolProto.LimitUpdateRequest.newBuilder() + .setCardNo("1000000000123456") + .setPileCode("20231212000010") + .setGunCode("01") + .setLimitYuan("1000") + .build()); + + return ResponseEntity.ok("success"); + } + + @GetMapping("/api/offlineCardSyncRequest") + public ResponseEntity offlineCardSyncRequest() { + + List cardInfos = Lists.newArrayList(CardInfo.newBuilder().setCardNo("1000000000123456").setLogicCardNo("1000000000123456").build(), + CardInfo.newBuilder().setCardNo("1000000000123457").setLogicCardNo("1000000000123457").build(), + CardInfo.newBuilder().setCardNo("1000000000123458").setLogicCardNo("1000000000123458").build()); + + pileProtocolService.offlineCardSyncRequest(OfflineCardSyncRequest.newBuilder() + .setPileCode("20231212000010") + .setTotal(cardInfos.size()) + .addAllCardInfo(cardInfos) + .build()); + + return ResponseEntity.ok("success"); + } + } \ No newline at end of file diff --git a/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java b/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java index 00b5e2d..63fd7e6 100644 --- a/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java +++ b/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java @@ -136,4 +136,23 @@ public interface PileProtocolService { */ void postLockStatus(UplinkQueueMessage uplinkQueueMessage, Callback callback); + /** + * 远程账户余额更新 + */ + void limitUpdateRequest(ProtocolProto.LimitUpdateRequest request); + + /** + * 远程账户余额更新应答 + */ + void onLimitUpdateResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback); + + /** + * 离线卡数据同步 + */ + void offlineCardSyncRequest(ProtocolProto.OfflineCardSyncRequest request); + + /** + * 离线卡数据同步应答 + */ + void onOfflineCardSyncResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback); } \ No newline at end of file diff --git a/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java b/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java index 1cddcd2..2dddf2d 100644 --- a/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java +++ b/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java @@ -444,12 +444,63 @@ public class DefaultPileProtocolService implements PileProtocolService { int parkStatus = groundLockStatusProto.getParkStatus(); int lockBattery = groundLockStatusProto.getLockBattery(); int alarmStatus = groundLockStatusProto.getAlarmStatus(); - - log.info("地锁状态信息: 桩编码: {}, 枪号: {}, 车位锁状态: {}, 车位状态: {}, 地锁电量: {}%, 报警状态: {}", + + log.info("地锁状态信息: 桩编码: {}, 枪号: {}, 车位锁状态: {}, 车位状态: {}, 地锁电量: {}%, 报警状态: {}", pileCode, gunCode, lockStatus, parkStatus, lockBattery, alarmStatus); - + // TODO 处理相关业务逻辑,比如保存地锁状态信息到数据库 - + + callback.onSuccess(); + } + + + @Override + public void onLimitUpdateResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback) { + log.info("接收到充电桩远程账户余额更新应答 {}", uplinkQueueMessage); + + // TODO 处理相关业务逻辑 + + callback.onSuccess(); + } + + @Override + public void limitUpdateRequest(LimitUpdateRequest 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.LIMIT_UPDATE_REQUEST.name()) + .setLimitUpdateRequest(request); + downlinkCallService.sendDownlinkMessage(downlinkRequestMessageBuilder,request.getPileCode()); + } + + @Override + public void offlineCardSyncRequest(OfflineCardSyncRequest 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_SYNC_REQUEST.name()) + .setOfflineCardSyncRequest(request); + downlinkCallService.sendDownlinkMessage(downlinkRequestMessageBuilder,request.getPileCode()); + } + + @Override + public void onOfflineCardSyncResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback) { + log.info("接收到充电桩离线卡数据同步应答 {}", uplinkQueueMessage); + + // TODO 处理相关业务逻辑 + callback.onSuccess(); } diff --git a/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java b/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java index 405a7ae..577774e 100644 --- a/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java +++ b/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java @@ -223,7 +223,15 @@ public class ProtocolUplinkConsumerService extends AbstractConsumerService imple } else if (uplinkQueueMsg.hasGroundLockStatusProto()) { pileProtocolService.postLockStatus(uplinkQueueMsg, callback); - + + } else if (uplinkQueueMsg.hasLimitUpdateResponse()) { + + pileProtocolService.onLimitUpdateResponse(uplinkQueueMsg, callback); + + } else if (uplinkQueueMsg.hasOfflineCardSyncResponse()) { + + pileProtocolService.onOfflineCardSyncResponse(uplinkQueueMsg, callback); + } else { callback.onSuccess(); diff --git a/jcpp-infrastructure-proto/src/main/proto/protocol.proto b/jcpp-infrastructure-proto/src/main/proto/protocol.proto index d6c6d4f..69f8d4f 100644 --- a/jcpp-infrastructure-proto/src/main/proto/protocol.proto +++ b/jcpp-infrastructure-proto/src/main/proto/protocol.proto @@ -74,6 +74,8 @@ message UplinkQueueMessage { BmsHandshakeProto bmsHandshakeProto = 37; OtaResponse otaResponse = 38; GroundLockStatusProto groundLockStatusProto = 39; + LimitUpdateResponse limitUpdateResponse = 40; + OfflineCardSyncResponse offlineCardSyncResponse = 41; } @@ -97,6 +99,8 @@ message DownlinkRequestMessage { TransactionRecordResponse transactionRecordResponse = 27; RestartPileRequest restartPileRequest = 28; OtaRequest otaRequest = 29; + LimitUpdateRequest limitUpdateRequest = 30; + OfflineCardSyncRequest offlineCardSyncRequest = 31; } message DownlinkResponseMessage { @@ -433,4 +437,36 @@ message GroundLockStatusProto { int32 alarmStatus = 7; // 报警状态 int32 reserved = 8; // 预留位 optional string additionalInfo = 20; // 附加信息 +} + +message LimitUpdateRequest { + string pileCode = 1; // 充电桩编码 + string gunCode = 2; // 枪编号 + string cardNo = 3; // 物理卡号 + string limitYuan = 4; // 余额 +} + +message LimitUpdateResponse { + string pileCode = 1; // 充电桩编码 + string cardNo = 2; // 物理卡号 + bool success = 3; + optional string errorMsg = 4; +} + +message OfflineCardSyncRequest { + string pileCode = 1; // 充电桩编码 + int32 total = 2; // 下发卡个数 + repeated CardInfo cardInfo = 3; // 卡号集合 +} + +message CardInfo { + string cardNo = 1; // 物理卡号 + string logicCardNo = 2; // 逻辑卡号 +} + + +message OfflineCardSyncResponse { + string pileCode = 1; // 充电桩编码 + bool success = 3; + optional string errorMsg = 4; } \ No newline at end of file diff --git a/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java b/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java index 7c79fd7..8fb72db 100644 --- a/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java +++ b/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java @@ -30,4 +30,8 @@ public enum DownlinkCmdEnum { REMOTE_RESTART_PILE, OTA_REQUEST, + + LIMIT_UPDATE_REQUEST, + + OFFLINE_CARD_SYNC_REQUEST } \ No newline at end of file diff --git a/jcpp-protocol-bootstrap/src/main/resources/log4j2.xml b/jcpp-protocol-bootstrap/src/main/resources/log4j2.xml index a0b7132..412fc0e 100644 --- a/jcpp-protocol-bootstrap/src/main/resources/log4j2.xml +++ b/jcpp-protocol-bootstrap/src/main/resources/log4j2.xml @@ -2,7 +2,7 @@ - /home/sanbing/logs/jcpp + ./logs/jcpp %d{yyyy-MM-dd HH:mm:ss:SSS} [%X{TRACE_ID}] [%t] %p %c{1} %m%n%throwable diff --git a/jcpp-protocol-yunkuaichong/READMD.md b/jcpp-protocol-yunkuaichong/READMD.md index 65f1c02..21991bb 100644 --- a/jcpp-protocol-yunkuaichong/READMD.md +++ b/jcpp-protocol-yunkuaichong/READMD.md @@ -95,9 +95,24 @@ `68 62 0300 00 94 20231212000010 01 c8 00 68 74 74 70 3a 2f 2f 31 32 37 2e 30 2e 30 2e 31 90 00 62 61 77 61 6e 00 00 00 00 00 00 00 00 00 00 00 31 32 33 31 32 33 00 00 00 00 00 00 00 00 00 00 2f 75 73 65 72 2f 64 61 74 61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 53 b6` #### 0x93 远程更新应答 -`68 0C 0300 00 93 20231212000010 00 7E9B` +`68 0C 03 00 00 93 20 23 12 12 00 00 10 00 7E 9B` --- #### 0x61 地锁数据上送 -`68 14 00 01 00 61 20 23 12 12 00 00 10 01 00 00 00 00 00 00 00 00 3D 6D` \ No newline at end of file +`68 14 00 01 00 61 20 23 12 12 00 00 10 01 00 00 00 00 00 00 00 00 3D 6D` +#### 0x42 远程账户余额更新 +`68 18 04 00 00 42 20 23 12 12 00 00 10 01 30 31 00 00 00 00 00 00 a0 86 01 00 4e ac` + +#### 0x41 远程账户余额更新应答 +`68 14 19 00 00 41 20 23 12 12 00 00 10 10 00 00 00 00 12 34 56 00 bc 16` + + +#### 0x44 离线卡数据同步 +`68 3f 02 00 00 44 20 23 12 12 00 00 10 03 00 00 00 10 00 00 00 00 12 34 56 10 00 00 00 00 12 34 56 10 00 00 00 00 12 34 57 10 00 00 00 00 12 34 57 10 00 00 00 00 12 34 58 10 00 00 00 00 12 34 58 ba 94` + +#### 0x43 离线卡数据同步应答 +#### 成功 +`68 0d 19 00 00 43 20 23 12 12 00 00 10 01 00 38 83` +#### 失败 +`68 0d 19 00 00 43 20 23 12 12 00 00 10 00 01 f8 d3` \ No newline at end of file diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/AbstractYunKuaiChongCmdExe.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/AbstractYunKuaiChongCmdExe.java index 0c49a3a..4e4281f 100644 --- a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/AbstractYunKuaiChongCmdExe.java +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/AbstractYunKuaiChongCmdExe.java @@ -41,6 +41,10 @@ public class AbstractYunKuaiChongCmdExe { private static final DecimalFormat PRICING_ID_DECIMAL_FORMAT = new DecimalFormat("0000"); + + protected static final String UNKNOWN_MSG = "未知的异常"; + + protected static String decodeTradeNo(byte[] tradeNo) { String tradeNoStr = BCDUtil.toString(tradeNo); return CharSequenceUtil.strip(tradeNoStr, "0", null); diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/enums/YunKuaiChongDownlinkCmdEnum.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/enums/YunKuaiChongDownlinkCmdEnum.java index 7671fdc..5456171 100644 --- a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/enums/YunKuaiChongDownlinkCmdEnum.java +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/enums/YunKuaiChongDownlinkCmdEnum.java @@ -40,6 +40,11 @@ public enum YunKuaiChongDownlinkCmdEnum { OTA_REQUEST(0x94), + LIMIT_UPDATE_REQUEST(0x42), + + OFFLINE_CARD_SYNC_REQUEST(0x44), + + ; private final Integer cmd; diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LimitUpdateRequestDLCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LimitUpdateRequestDLCmd.java new file mode 100644 index 0000000..a07d9e8 --- /dev/null +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LimitUpdateRequestDLCmd.java @@ -0,0 +1,54 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; + +import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.LIMIT_UPDATE_REQUEST; + +import java.math.BigDecimal; + +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.ProtocolProto; +import sanbing.jcpp.protocol.ProtocolContext; +import sanbing.jcpp.protocol.listener.tcp.TcpSession; +import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe; +import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage; +import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd; + + +/** + * 云快充1.5.0 远程账户余额更新 + * + * @author bawan + */ +@Slf4j +@YunKuaiChongCmd(0x42) +public class YunKuaiChongV150LimitUpdateRequestDLCmd extends YunKuaiChongDownlinkCmdExe { + + @Override + public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage message, ProtocolContext ctx) { + log.info("{} 云快充1.5.0 远程账户余额更新", tcpSession); + + if (!message.getMsg().hasLimitUpdateRequest()) { + log.error("云快充1.5.0 远程账户余额更新消息体为空"); + return; + } + + // 初始化 buf + ByteBuf msgBody = Unpooled.buffer(20); + ProtocolProto.LimitUpdateRequest request = message.getMsg().getLimitUpdateRequest(); + msgBody.writeBytes(encodePileCode(request.getPileCode())); + msgBody.writeBytes(encodeGunCode(request.getGunCode())); + msgBody.writeBytes(BCDUtil.toBytes(request.getCardNo())); + msgBody.writeIntLE(new BigDecimal(request.getLimitYuan()).movePointRight(2).intValue()); + + super.encodeAndWriteFlush(LIMIT_UPDATE_REQUEST, msgBody, tcpSession); + } + +} diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LimitUpdateResponseULCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LimitUpdateResponseULCmd.java new file mode 100644 index 0000000..42ad93d --- /dev/null +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LimitUpdateResponseULCmd.java @@ -0,0 +1,78 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; + +import java.util.Map; + +import cn.hutool.core.text.CharSequenceUtil; +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.ProtocolProto; +import sanbing.jcpp.protocol.ProtocolContext; +import sanbing.jcpp.protocol.listener.tcp.TcpSession; +import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe; +import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage; +import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd; + + +/** + * 云快充1.5.0 余额更新应答 + * + * @author bawan + */ +@Slf4j +@YunKuaiChongCmd(0x41) +public class YunKuaiChongV150LimitUpdateResponseULCmd extends YunKuaiChongUplinkCmdExe { + + private static final Map UPDATE_RESULT; + + static { + UPDATE_RESULT = Map.of( + (byte) 0x00,"修改成功", + (byte) 0x01,"设备编号错误", + (byte) 0x02,"卡号错误" + ); + } + + + + @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); + + // 物理卡号 + String cardNo = CharSequenceUtil.EMPTY; + if(byteBuf.readableBytes() >= 8) { + byte[] cardNoBytes = new byte[8]; + byteBuf.readBytes(cardNoBytes); + cardNo = BCDUtil.toString(cardNoBytes); + } + + // 修改结果 0x00-修改成功 0x01-设备编号错误 0x02-卡号错误 + byte updateResult = byteBuf.readByte(); + + ProtocolProto.UplinkQueueMessage queueMessage = uplinkMessageBuilder(pileCode, tcpSession, message) + .setLimitUpdateResponse(ProtocolProto.LimitUpdateResponse.newBuilder() + .setPileCode(pileCode) + .setCardNo(cardNo) + .setSuccess(updateResult == 0x00) + .setErrorMsg(UPDATE_RESULT.getOrDefault(updateResult,UNKNOWN_MSG)) + .build()) + .build(); + // 转发到后端 + tcpSession.getForwarder().sendMessage(queueMessage); + } + +} diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OfflineCardSyncRequestDLCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OfflineCardSyncRequestDLCmd.java new file mode 100644 index 0000000..eebddb2 --- /dev/null +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OfflineCardSyncRequestDLCmd.java @@ -0,0 +1,74 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; + +import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.OFFLINE_CARD_SYNC_REQUEST; + +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.ProtocolProto; +import sanbing.jcpp.protocol.ProtocolContext; +import sanbing.jcpp.protocol.listener.tcp.TcpSession; +import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe; +import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage; +import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd; + + +/** + * 云快充1.5.0 离线卡数据同步 + * + * @author bawan + */ +@Slf4j +@YunKuaiChongCmd(0x44) +public class YunKuaiChongV150OfflineCardSyncRequestDLCmd extends YunKuaiChongDownlinkCmdExe { + + @Override + public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage message, ProtocolContext ctx) { + log.info("{} 云快充1.5.0 离线卡数据同步", tcpSession); + + if (!message.getMsg().hasOfflineCardSyncRequest()) { + log.error("云快充1.5.0 离线卡数据同步消息体为空"); + return; + } + + ProtocolProto.OfflineCardSyncRequest request = message.getMsg().getOfflineCardSyncRequest(); + + if (request.getTotal() > 15) { + log.error("云快充1.5.0 离线卡数据同步 下发卡个数最大支持: 15个当前: {}个", request.getTotal()); + return; + } + // 初始化 buf + ByteBuf msgBody = Unpooled.buffer(bufferInitialCapacity(request)); + 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())); + }); + + super.encodeAndWriteFlush(OFFLINE_CARD_SYNC_REQUEST, msgBody, tcpSession); + } + + + /** + * 桩编号 BCD 码 7 + * 下发卡个数 BIN 码 1 最大 15 个 + * n卡逻辑卡号 BCD 码 8 离线卡逻辑卡号 + * ........ ........ ........ ........ + * n卡物理卡号 BIN 码 8 离线卡物理卡号 + * @param request request + * @return bufferInitialCapacity + */ + private int bufferInitialCapacity(ProtocolProto.OfflineCardSyncRequest request) { + return (8 + 8) * request.getCardInfoCount() + 7 + 1; + } + + +} diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OfflineCardSyncResponseULCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OfflineCardSyncResponseULCmd.java new file mode 100644 index 0000000..3297ff1 --- /dev/null +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OfflineCardSyncResponseULCmd.java @@ -0,0 +1,92 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; + + +import java.util.Map; + +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.ProtocolProto; +import sanbing.jcpp.protocol.ProtocolContext; +import sanbing.jcpp.protocol.listener.tcp.TcpSession; +import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe; +import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage; +import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd; + + +/** + * 云快充1.5.0 离线卡数据同步应答 + * + * @author bawan + */ +@Slf4j +@YunKuaiChongCmd(0x43) +public class YunKuaiChongV150OfflineCardSyncResponseULCmd extends YunKuaiChongUplinkCmdExe { + + private static final Map> FAILURE_REASON; + + + private static final String SUCCESS = "成功"; + + + static { + FAILURE_REASON = Map.of( + (byte) 0x00,Map.of((byte)0x01,"卡号格式错误",(byte)0x02,"储存空间不足"), + (byte) 0x01,Map.of((byte)0x00,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); + + // 保存结果 0x00-失败 0x01-成功 + byte saveResult = byteBuf.readByte(); + byte failureReason = 0x00; + + if (byteBuf.readableBytes() >= 1) { + // 失败原因 0x01-卡号格式错误 0x02-储存空间不足 + failureReason = byteBuf.readByte(); + } + + ProtocolProto.UplinkQueueMessage queueMessage = uplinkMessageBuilder(pileCode, tcpSession, message) + .setOfflineCardSyncResponse(ProtocolProto.OfflineCardSyncResponse.newBuilder() + .setPileCode(pileCode) + .setSuccess(saveResult == 0x01) + .setErrorMsg(errorMsg(saveResult, failureReason)) + .build()) + .build(); + // 转发到后端 + tcpSession.getForwarder().sendMessage(queueMessage); + } + + + private String errorMsg(byte saveResult, byte failureReason) { + if(saveResult == 0x01) { + return SUCCESS; + } + Map saveResultMap = FAILURE_REASON.get(saveResult); + if(null == saveResultMap) { + return UNKNOWN_MSG; + } + return saveResultMap.getOrDefault(failureReason,UNKNOWN_MSG); + } + + + +} + diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OtaResponseULCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OtaResponseULCmd.java index f018262..eee4a02 100644 --- a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OtaResponseULCmd.java +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150OtaResponseULCmd.java @@ -58,7 +58,7 @@ public class YunKuaiChongV150OtaResponseULCmd extends YunKuaiChongUplinkCmdExe { .setOtaResponse(ProtocolProto.OtaResponse.newBuilder() .setPileCode(pileCode) .setSuccess(upgradeStatus == 0x00) - .setErrorMsg(UPGRADE_STATUS.get(upgradeStatus)) + .setErrorMsg(UPGRADE_STATUS.getOrDefault(upgradeStatus,UNKNOWN_MSG)) .build()) .build(); // 转发到后端