mirror of
https://gitee.com/san-bing/JChargePointProtocol
synced 2026-05-04 18:09:54 +08:00
!33 新增云快充启动充电的逻辑卡号和物理卡号,和双枪并充序号以及双枪并充的测试接口
* 新增云快充启动充电的逻辑卡号和物理卡号,和双枪并充序号以及双枪并充的测试接口 * CMD路由优化 * Merge remote-tracking branch 'gitee/master' into Feat_Lvneng_module_optimize * cmd路由优化 * cmd路由优化 * 绿能模块优化 * 新增云快充1.7 0x3D * 添加停止充电的TestController
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
|
||||
* 微信:mohan_88888
|
||||
* 抖音:程序员三丙
|
||||
* 付费课程知识星球:https://t.zsxq.com/aKtXo
|
||||
*/
|
||||
package sanbing.jcpp.protocol.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 通用协议命令注解
|
||||
* 所有协议的命令类都应该使用此注解
|
||||
*
|
||||
* @author sanbing
|
||||
* @since 2024-12-16
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface ProtocolCmd {
|
||||
|
||||
/**
|
||||
* 命令字值
|
||||
*/
|
||||
int value();
|
||||
|
||||
/**
|
||||
* 支持的协议名列表,必须明确指定
|
||||
*/
|
||||
String[] protocolNames();
|
||||
}
|
||||
@@ -13,10 +13,14 @@ public enum DownlinkCmdEnum {
|
||||
|
||||
LOGIN_ACK,
|
||||
|
||||
HEARTBEAT_ACK,
|
||||
|
||||
VERIFY_PRICING_ACK,
|
||||
|
||||
QUERY_PRICING_ACK,
|
||||
|
||||
REAL_TIME_DATA_ACK,
|
||||
|
||||
SET_PRICING,
|
||||
|
||||
REMOTE_START_CHARGING,
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
|
||||
* 微信:mohan_88888
|
||||
* 抖音:程序员三丙
|
||||
* 付费课程知识星球:https://t.zsxq.com/aKtXo
|
||||
*/
|
||||
package sanbing.jcpp.protocol.executor;
|
||||
|
||||
import sanbing.jcpp.protocol.ProtocolContext;
|
||||
import sanbing.jcpp.protocol.domain.ProtocolSession;
|
||||
|
||||
/**
|
||||
* 通用协议下行命令执行器接口
|
||||
*
|
||||
* @param <T> 下行消息类型
|
||||
* @author sanbing
|
||||
* @since 2024-12-16
|
||||
*/
|
||||
public interface ProtocolDownlinkCmdExe<T> {
|
||||
|
||||
/**
|
||||
* 执行下行命令
|
||||
*
|
||||
* @param session TCP会话
|
||||
* @param downlinkMessage 下行消息
|
||||
* @param protocolContext 协议上下文
|
||||
*/
|
||||
void execute(ProtocolSession session, T downlinkMessage, ProtocolContext protocolContext);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
|
||||
* 微信:mohan_88888
|
||||
* 抖音:程序员三丙
|
||||
* 付费课程知识星球:https://t.zsxq.com/aKtXo
|
||||
*/
|
||||
package sanbing.jcpp.protocol.executor;
|
||||
|
||||
import sanbing.jcpp.protocol.ProtocolContext;
|
||||
import sanbing.jcpp.protocol.domain.ProtocolSession;
|
||||
|
||||
/**
|
||||
* 通用协议上行命令执行器接口
|
||||
*
|
||||
* @param <T> 上行消息类型
|
||||
* @author sanbing
|
||||
* @since 2024-12-16
|
||||
*/
|
||||
public interface ProtocolUplinkCmdExe<T> {
|
||||
|
||||
/**
|
||||
* 执行上行命令
|
||||
*
|
||||
* @param session TCP会话
|
||||
* @param uplinkMessage 上行消息
|
||||
* @param protocolContext 协议上下文
|
||||
*/
|
||||
void execute(ProtocolSession session, T uplinkMessage, ProtocolContext protocolContext);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
|
||||
* 微信:mohan_88888
|
||||
* 抖音:程序员三丙
|
||||
* 付费课程知识星球:https://t.zsxq.com/aKtXo
|
||||
*/
|
||||
package sanbing.jcpp.protocol.mapping;
|
||||
|
||||
import sanbing.jcpp.protocol.domain.DownlinkCmdEnum;
|
||||
|
||||
/**
|
||||
* 下行命令转换器接口
|
||||
*
|
||||
* 每个协议模块都应该实现此接口,提供从通用下行命令到协议特定命令的转换
|
||||
*
|
||||
* @author sanbing
|
||||
* @since 2024-12-16
|
||||
*/
|
||||
public interface DownlinkCmdConverter {
|
||||
|
||||
/**
|
||||
* 将通用下行命令转换为协议特定的命令字
|
||||
*
|
||||
* @param downlinkCmd 通用下行命令
|
||||
* @return 协议特定的命令字,如果不支持该命令则返回 null
|
||||
*/
|
||||
Integer convertToCmd(DownlinkCmdEnum downlinkCmd);
|
||||
|
||||
/**
|
||||
* 检查是否支持指定的下行命令
|
||||
*
|
||||
* @param downlinkCmd 通用下行命令
|
||||
* @return 是否支持
|
||||
*/
|
||||
default boolean supports(DownlinkCmdEnum downlinkCmd) {
|
||||
return convertToCmd(downlinkCmd) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议名称
|
||||
*
|
||||
* @return 协议名称
|
||||
*/
|
||||
String getProtocolName();
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
|
||||
* 微信:mohan_88888
|
||||
* 抖音:程序员三丙
|
||||
* 付费课程知识星球:https://t.zsxq.com/aKtXo
|
||||
*/
|
||||
package sanbing.jcpp.protocol.routing;
|
||||
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* 通用命令路由器
|
||||
*
|
||||
* 提供基于协议名+命令字的路由功能,支持多版本协议
|
||||
*
|
||||
* @param <T> 命令执行器类型
|
||||
* @author sanbing
|
||||
* @since 2025-08-25
|
||||
*/
|
||||
@Slf4j
|
||||
public class ProtocolCommandRouter<T> {
|
||||
|
||||
private final Map<String, T> executorMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param scanBaseClass 要扫描的包的代表类
|
||||
* @param executorFilter 执行器过滤器,判断类是否为目标执行器类型
|
||||
*/
|
||||
public ProtocolCommandRouter(Class<?> scanBaseClass, Predicate<Class<?>> executorFilter) {
|
||||
initializeRoutes(scanBaseClass, executorFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化路由表
|
||||
*/
|
||||
private void initializeRoutes(Class<?> scanBaseClass, Predicate<Class<?>> executorFilter) {
|
||||
Set<Class<?>> cmdClasses = ClassUtil.scanPackageByAnnotation(
|
||||
ClassUtil.getPackage(scanBaseClass),
|
||||
ProtocolCmd.class
|
||||
);
|
||||
|
||||
cmdClasses.stream()
|
||||
.filter(executorFilter)
|
||||
.forEach(this::registerExecutor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册命令执行器
|
||||
*/
|
||||
private void registerExecutor(Class<?> executorClass) {
|
||||
ProtocolCmd annotation = executorClass.getAnnotation(ProtocolCmd.class);
|
||||
if (annotation == null) {
|
||||
log.warn("类 {} 没有 @ProtocolCmd 注解", executorClass.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
int cmd = annotation.value();
|
||||
String[] protocolNames = annotation.protocolNames();
|
||||
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
T executor = (T) executorClass.getDeclaredConstructor().newInstance();
|
||||
|
||||
for (String protocolName : protocolNames) {
|
||||
String key = buildKey(protocolName, cmd);
|
||||
executorMap.put(key, executor);
|
||||
log.debug("注册命令执行器: {} -> {}", key, executorClass.getSimpleName());
|
||||
}
|
||||
} catch (InstantiationException | IllegalAccessException |
|
||||
InvocationTargetException | NoSuchMethodException e) {
|
||||
log.error("无法实例化命令执行器 {}: {}", executorClass.getName(), e.getMessage());
|
||||
throw new RuntimeException("Failed to instantiate command executor: " + executorClass.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取命令执行器
|
||||
*
|
||||
* @param protocolName 协议名称
|
||||
* @param cmd 命令字
|
||||
* @return 命令执行器,如果未找到则返回 null
|
||||
*/
|
||||
public T getExecutor(String protocolName, int cmd) {
|
||||
String key = buildKey(protocolName, cmd);
|
||||
return executorMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建路由键
|
||||
*/
|
||||
private String buildKey(String protocolName, int cmd) {
|
||||
return protocolName + ":" + cmd;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user