修正云快充OTA升级中的一些BUG,并优化代码

This commit is contained in:
三丙
2025-08-13 20:02:41 +08:00
parent 80fb741692
commit b393f5b426
10 changed files with 110 additions and 44 deletions

View File

@@ -155,11 +155,11 @@ public class TestController {
}
@GetMapping("/api/remoteUpdate")
public ResponseEntity<String> remoteUpdate() {
@GetMapping("/api/otaRequest")
public ResponseEntity<String> otaRequest() {
pileProtocolService.remoteUpdate(ProtocolProto.OtaRequest.newBuilder()
.setAddress("http://127.0.0.1")
pileProtocolService.otaRequest(ProtocolProto.OtaRequest.newBuilder()
.setAddress("127.0.0.1")
.setExecutionControl(1)
.setDownloadTimeout(1)
.setPassword("123123")

View File

@@ -115,12 +115,12 @@ public interface PileProtocolService {
/**
* 远程更新
*/
void remoteUpdate(ProtocolProto.OtaRequest request);
void otaRequest(ProtocolProto.OtaRequest request);
/**
* 远程更新应答
*/
void onRemoteUpdate(UplinkQueueMessage uplinkQueueMessage, Callback callback);
void onOtaResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback);
/*
* BMS充电握手

View File

@@ -379,7 +379,7 @@ public class DefaultPileProtocolService implements PileProtocolService {
}
@Override
public void remoteUpdate(OtaRequest request) {
public void otaRequest(OtaRequest request) {
UUID messageId = UUID.randomUUID();
UUID requestId = UUID.randomUUID();
@@ -390,14 +390,14 @@ public class DefaultPileProtocolService implements PileProtocolService {
.setPileCode(request.getPileCode())
.setRequestIdMSB(requestId.getMostSignificantBits())
.setRequestIdLSB(requestId.getLeastSignificantBits())
.setDownlinkCmd(DownlinkCmdEnum.REMOTE_UPDATE.name())
.setDownlinkCmd(DownlinkCmdEnum.OTA_REQUEST.name())
.setOtaRequest(request);
downlinkCallService.sendDownlinkMessage(downlinkRequestMessageBuilder,request.getPileCode());
}
@Override
public void onRemoteUpdate(UplinkQueueMessage uplinkQueueMessage, Callback callback) {
public void onOtaResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback) {
log.info("接收到充电桩更新应答 {}", uplinkQueueMessage);

View File

@@ -218,7 +218,7 @@ public class ProtocolUplinkConsumerService extends AbstractConsumerService imple
} else if (uplinkQueueMsg.hasOtaResponse()) {
pileProtocolService.onRemoteUpdate(uplinkQueueMsg, callback);
pileProtocolService.onOtaResponse(uplinkQueueMsg, callback);
} else {

View File

@@ -29,5 +29,5 @@ public enum DownlinkCmdEnum {
REMOTE_RESTART_PILE,
REMOTE_UPDATE,
OTA_REQUEST,
}

View File

@@ -91,4 +91,8 @@
---
#### 0x94 远程更新
`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`

View File

@@ -18,6 +18,7 @@ import sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.time.LocalTime;
import java.util.List;
@@ -153,22 +154,71 @@ public class AbstractYunKuaiChongCmdExe {
return new BigDecimal(value).divide(new BigDecimal(magnification), scale, RoundingMode.HALF_UP);
}
protected static ByteBuf writeParamFillZero(String param,int maxLength) {
if (param.length() > maxLength) {
throw new IllegalArgumentException(String.format("云快充1.5.0 param: %s too large",param));
/**
* 高性能版本直接写入目标ByteBuf避免创建中间ByteBuf对象
* 将字符串参数写入ByteBuf不足指定长度用0填充右侧填充
* 使用ASCII编码适用于协议中的字符串字段
*
* @param target 目标ByteBuf
* @param param 要写入的字符串参数可以为null
* @param maxLength 目标长度(字节数)
* @throws IllegalArgumentException 如果参数字节长度超过maxLength
*/
protected static void writeParamFillZero(ByteBuf target, String param, int maxLength) {
if (maxLength <= 0) {
throw new IllegalArgumentException("maxLength must be positive");
}
if (param == null) {
param = "";
}
// 使用ASCII编码适用于协议字段
byte[] paramBytes = param.getBytes(StandardCharsets.US_ASCII);
// 检查长度
if (paramBytes.length > maxLength) {
throw new IllegalArgumentException(
String.format("云快充1.5.0 参数: %s 字节长度 %d 超过最大长度 %d",
param, paramBytes.length, maxLength));
}
// 确保目标ByteBuf有足够的写入空间
target.ensureWritable(maxLength);
// 写入数据
target.writeBytes(paramBytes);
// 填充剩余空间
int remainingBytes = maxLength - paramBytes.length;
if (remainingBytes > 0) {
target.writeZero(remainingBytes);
}
ByteBuf msgBody = Unpooled.buffer(maxLength);
msgBody.writeBytes(param.getBytes());
msgBody.writeZero(maxLength-param.length());
return msgBody;
}
protected static ByteBuf writeParamFillZero(int param,int maxLength) {
ByteBuf msgBody = Unpooled.buffer(maxLength);
msgBody.writeByte(param);
int index = msgBody.writerIndex();
msgBody.writeZero(maxLength-index);
return msgBody;
/**
* 高性能版本将整数参数作为字节值直接写入ByteBuf不足指定长度用0填充右侧填充
*
* @param target 目标ByteBuf
* @param param 要写入的整数参数将作为字节值写入只使用低8位
* @param maxLength 目标长度(字节数)
*/
protected static void writeParamFillZero(ByteBuf target, int param, int maxLength) {
if (maxLength <= 0) {
throw new IllegalArgumentException("maxLength must be positive");
}
// 确保目标ByteBuf有足够的写入空间
target.ensureWritable(maxLength);
// 将整数作为字节值写入只使用低8位
target.writeByte(param & 0xFF);
// 计算剩余空间并填充0
int remainingBytes = maxLength - 1; // 已经写入了1个字节
if (remainingBytes > 0) {
target.writeZero(remainingBytes);
}
}
}

View File

@@ -38,7 +38,7 @@ public enum YunKuaiChongDownlinkCmdEnum {
REMOTE_RESTART_PILE(0x92),
REMOTE_UPDATE(0x94),
OTA_REQUEST(0x94),
;
private final Integer cmd;

View File

@@ -1,52 +1,58 @@
/**
* 开源代码仅供学习和交流研究使用商用请联系三丙
* 微信mohan_88888
* 抖音程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.yunkuaichong.v150.cmd;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.REMOTE_UPDATE;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.proto.gen.ProtocolProto;
import sanbing.jcpp.proto.gen.ProtocolProto.OtaRequest;
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;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.OTA_REQUEST;
/**
* 云快充1.5.0 远程更新
*
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(0x94)
public class YunKuaiChongV150RemoteUpdateDLCmd extends YunKuaiChongDownlinkCmdExe {
public class YunKuaiChongV150OtaRequestDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage message, ProtocolContext ctx) {
log.info("{} 云快充1.5.0 远程更新", tcpSession);
// check
if (message.getMsg().hasOtaRequest()) {
if (!message.getMsg().hasOtaRequest()) {
log.error("云快充1.5.0 远程更新消息体为空");
return;
}
// 初始化 buf
ByteBuf msgBody = Unpooled.buffer(94);
// buf 转换
ProtocolProto.OtaRequest request = message.getMsg().getOtaRequest();
// buf 转换 - 使用高性能版本直接写入避免创建中间ByteBuf对象
OtaRequest request = message.getMsg().getOtaRequest();
msgBody.writeBytes(encodePileCode(request.getPileCode()));
msgBody.writeByte(request.getPileModel());
msgBody.writeBytes(writeParamFillZero(request.getPilePower(),2));
msgBody.writeBytes(writeParamFillZero(request.getAddress(),16));
msgBody.writeBytes(writeParamFillZero(request.getPort(),2));
msgBody.writeBytes(writeParamFillZero(request.getUsername(),16));
msgBody.writeBytes(writeParamFillZero(request.getPassword(),16));
msgBody.writeBytes(writeParamFillZero(request.getFilePath(),32));
writeParamFillZero(msgBody, request.getPilePower(), 2);
writeParamFillZero(msgBody, request.getAddress(), 16);
writeParamFillZero(msgBody, request.getPort(), 2);
writeParamFillZero(msgBody, request.getUsername(), 16);
writeParamFillZero(msgBody, request.getPassword(), 16);
writeParamFillZero(msgBody, request.getFilePath(), 32);
msgBody.writeByte(request.getExecutionControl());
msgBody.writeByte(request.getDownloadTimeout());
super.encodeAndWriteFlush(REMOTE_UPDATE,msgBody,tcpSession);
super.encodeAndWriteFlush(OTA_REQUEST, msgBody, tcpSession);
}
}

View File

@@ -1,7 +1,11 @@
/**
* 开源代码仅供学习和交流研究使用商用请联系三丙
* 微信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;
@@ -13,6 +17,8 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.util.Map;
/**
* 云快充1.5.0 远程更新应答
@@ -21,7 +27,7 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
*/
@Slf4j
@YunKuaiChongCmd(0x93)
public class YunKuaiChongV150RemoteUpdateAckULCmd extends YunKuaiChongUplinkCmdExe {
public class YunKuaiChongV150OtaResponseULCmd extends YunKuaiChongUplinkCmdExe {
private static final Map<Byte, String> UPGRADE_STATUS;