添加DRC控制
This commit is contained in:
parent
a53c531b47
commit
a377485b23
|
|
@ -0,0 +1,11 @@
|
|||
package com.tuoheng.status.machine.action.drc;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.platform.strategy.PlatformAction;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
|
||||
/**
|
||||
* Base action for DRC enter handling; platform implementations extend this.
|
||||
*/
|
||||
public abstract class EnterAction implements PlatformAction<DrcState, DrcEvent> {
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tuoheng.status.machine.action.drc;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.platform.strategy.PlatformAction;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
|
||||
/**
|
||||
* Base action for DRC entered handling; platform implementations extend this.
|
||||
*/
|
||||
public abstract class EnteredAction implements PlatformAction<DrcState, DrcEvent> {
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tuoheng.status.machine.action.drc;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.platform.strategy.PlatformAction;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
|
||||
/**
|
||||
* Base action for DRC exit handling; platform implementations extend this.
|
||||
*/
|
||||
public abstract class ExitAction implements PlatformAction<DrcState, DrcEvent> {
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tuoheng.status.machine.action.drc;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.platform.strategy.PlatformAction;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
|
||||
/**
|
||||
* Base action for DRC exited handling; platform implementations extend this.
|
||||
*/
|
||||
public abstract class ExitedAction implements PlatformAction<DrcState, DrcEvent> {
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
package com.tuoheng.status.machine.config;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.platform.factory.PlatformStrategyFactory;
|
||||
import com.tuoheng.status.machine.platform.strategy.DrcPlatformStrategy;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.config.StateMachineBuilder;
|
||||
import org.springframework.statemachine.config.StateMachineFactory;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* DRC(飞行控制模式)状态机配置(多平台支持版本)
|
||||
* 通过PlatformStrategyFactory动态获取平台特定的Guard、Action和Listener
|
||||
*/
|
||||
@Configuration
|
||||
public class DrcMachineConfig {
|
||||
|
||||
@Autowired
|
||||
private PlatformStrategyFactory platformStrategyFactory;
|
||||
|
||||
@Bean(name = "drcStateMachineFactory")
|
||||
public StateMachineFactory<DrcState, DrcEvent> drcStateMachineFactory() throws Exception {
|
||||
return new StateMachineFactory<DrcState, DrcEvent>() {
|
||||
@Override
|
||||
public StateMachine<DrcState, DrcEvent> getStateMachine() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachine<DrcState, DrcEvent> getStateMachine(String machineId) {
|
||||
try {
|
||||
// 根据机巢SN获取平台策略
|
||||
DrcPlatformStrategy strategy = platformStrategyFactory.getDrcStrategy(machineId);
|
||||
|
||||
StateMachineBuilder.Builder<DrcState, DrcEvent> builder = StateMachineBuilder.builder();
|
||||
configureDrcStateMachine(builder, strategy);
|
||||
configureDrcStates(builder);
|
||||
configureDrcTransitions(builder, strategy);
|
||||
|
||||
StateMachine<DrcState, DrcEvent> stateMachine = builder.build();
|
||||
stateMachine.getExtendedState().getVariables().put("machineId", machineId);
|
||||
return stateMachine;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to create DRC state machine for: " + machineId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachine<DrcState, DrcEvent> getStateMachine(UUID uuid) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void configureDrcStateMachine(
|
||||
StateMachineBuilder.Builder<DrcState, DrcEvent> builder,
|
||||
DrcPlatformStrategy strategy) throws Exception {
|
||||
builder.configureConfiguration()
|
||||
.withConfiguration()
|
||||
.autoStartup(true)
|
||||
.listener(strategy.getListener());
|
||||
}
|
||||
|
||||
private void configureDrcStates(StateMachineBuilder.Builder<DrcState, DrcEvent> builder) throws Exception {
|
||||
builder.configureStates()
|
||||
.withStates()
|
||||
.initial(DrcState.UNKNOWN)
|
||||
.states(EnumSet.allOf(DrcState.class));
|
||||
}
|
||||
|
||||
private void configureDrcTransitions(
|
||||
StateMachineBuilder.Builder<DrcState, DrcEvent> builder,
|
||||
DrcPlatformStrategy strategy) throws Exception {
|
||||
builder.configureTransitions()
|
||||
// ========== 从 UNKNOWN 到所有状态的转换(服务器重启后状态同步) ==========
|
||||
// UNKNOWN -> EXITED
|
||||
.withExternal()
|
||||
.source(DrcState.UNKNOWN)
|
||||
.target(DrcState.EXITED)
|
||||
.event(DrcEvent.EXITED)
|
||||
.and()
|
||||
|
||||
// UNKNOWN -> ENTERING
|
||||
.withExternal()
|
||||
.source(DrcState.UNKNOWN)
|
||||
.target(DrcState.ENTERING)
|
||||
.event(DrcEvent.ENTER)
|
||||
.and()
|
||||
|
||||
// UNKNOWN -> ENTERED
|
||||
.withExternal()
|
||||
.source(DrcState.UNKNOWN)
|
||||
.target(DrcState.ENTERED)
|
||||
.event(DrcEvent.ENTERED)
|
||||
.and()
|
||||
|
||||
// UNKNOWN -> EXITING
|
||||
.withExternal()
|
||||
.source(DrcState.UNKNOWN)
|
||||
.target(DrcState.EXITING)
|
||||
.event(DrcEvent.EXIT)
|
||||
.and()
|
||||
|
||||
// ========== 正常状态转换(带 Guard 和 Action) ==========
|
||||
// EXITED -> ENTERING
|
||||
.withExternal()
|
||||
.source(DrcState.EXITED)
|
||||
.target(DrcState.ENTERING)
|
||||
.event(DrcEvent.ENTER)
|
||||
.action(strategy.getEnterAction())
|
||||
.guard(strategy.getCanEnterGuard())
|
||||
.and()
|
||||
|
||||
// ENTERING -> ENTERED
|
||||
.withExternal()
|
||||
.source(DrcState.ENTERING)
|
||||
.target(DrcState.ENTERED)
|
||||
.event(DrcEvent.ENTERED)
|
||||
.action(strategy.getEnteredAction())
|
||||
.and()
|
||||
|
||||
// ENTERED -> EXITING
|
||||
.withExternal()
|
||||
.source(DrcState.ENTERED)
|
||||
.target(DrcState.EXITING)
|
||||
.event(DrcEvent.EXIT)
|
||||
.action(strategy.getExitAction())
|
||||
.guard(strategy.getCanExitGuard())
|
||||
.and()
|
||||
|
||||
// EXITING -> EXITED
|
||||
.withExternal()
|
||||
.source(DrcState.EXITING)
|
||||
.target(DrcState.EXITED)
|
||||
.event(DrcEvent.EXITED)
|
||||
.action(strategy.getExitedAction());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.tuoheng.status.machine.events;
|
||||
|
||||
/**
|
||||
* DRC(飞行控制模式)事件枚举
|
||||
* 定义DRC状态机中的所有事件
|
||||
*/
|
||||
public enum DrcEvent {
|
||||
/**
|
||||
* 进入DRC模式指令
|
||||
* 触发源: 用户指令
|
||||
*/
|
||||
ENTER,
|
||||
|
||||
/**
|
||||
* 进入DRC模式完成
|
||||
* 触发源: Events事件
|
||||
*/
|
||||
ENTERED,
|
||||
|
||||
/**
|
||||
* 退出DRC模式指令
|
||||
* 触发源: 用户指令/自动
|
||||
*/
|
||||
EXIT,
|
||||
|
||||
/**
|
||||
* 退出DRC模式完成
|
||||
* 触发源: Events事件
|
||||
*/
|
||||
EXITED
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tuoheng.status.machine.guard.drc;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.platform.strategy.PlatformGuard;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
|
||||
/**
|
||||
* Base guard for checking if can enter DRC mode; platform implementations extend this.
|
||||
*/
|
||||
public abstract class CanEnterGuard implements PlatformGuard<DrcState, DrcEvent> {
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tuoheng.status.machine.guard.drc;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.platform.strategy.PlatformGuard;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
|
||||
/**
|
||||
* Base guard for checking if can exit DRC mode; platform implementations extend this.
|
||||
*/
|
||||
public abstract class CanExitGuard implements PlatformGuard<DrcState, DrcEvent> {
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
package com.tuoheng.status.machine.listener;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.platform.strategy.PlatformListener;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* 默认DRC状态监听器
|
||||
* 提供基础的状态变化监听功能,各平台可以继承并定制
|
||||
*/
|
||||
public abstract class DefaultDrcListener implements PlatformListener<DrcState, DrcEvent> {
|
||||
|
||||
@Override
|
||||
public void stateChanged(State<DrcState, DrcEvent> from, State<DrcState, DrcEvent> to) {
|
||||
if (from != null && to != null) {
|
||||
System.out.println(String.format("[%s] 状态变化: %s -> %s",
|
||||
getName(), from.getId(), to.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateEntered(State<DrcState, DrcEvent> state) {
|
||||
System.out.println(String.format("[%s] 进入状态: %s", getName(), state.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateExited(State<DrcState, DrcEvent> state) {
|
||||
System.out.println(String.format("[%s] 退出状态: %s", getName(), state.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventNotAccepted(Message<DrcEvent> event) {
|
||||
System.out.println(String.format("[%s] 事件未被接受: %s", getName(), event.getPayload()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transition(Transition<DrcState, DrcEvent> transition) {
|
||||
// 默认不处理
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transitionStarted(Transition<DrcState, DrcEvent> transition) {
|
||||
if (transition.getSource() != null && transition.getTarget() != null) {
|
||||
System.out.println(String.format("[%s] 转换开始: %s -> %s",
|
||||
getName(), transition.getSource().getId(), transition.getTarget().getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transitionEnded(Transition<DrcState, DrcEvent> transition) {
|
||||
if (transition.getSource() != null && transition.getTarget() != null) {
|
||||
System.out.println(String.format("[%s] 转换结束: %s -> %s",
|
||||
getName(), transition.getSource().getId(), transition.getTarget().getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateMachineStarted(StateMachine<DrcState, DrcEvent> stateMachine) {
|
||||
String machineId = (String) stateMachine.getExtendedState().getVariables().get("machineId");
|
||||
System.out.println(String.format("[%s] 状态机启动: %s", getName(), machineId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateMachineStopped(StateMachine<DrcState, DrcEvent> stateMachine) {
|
||||
String machineId = (String) stateMachine.getExtendedState().getVariables().get("machineId");
|
||||
System.out.println(String.format("[%s] 状态机停止: %s", getName(), machineId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateMachineError(StateMachine<DrcState, DrcEvent> stateMachine, Exception exception) {
|
||||
String machineId = (String) stateMachine.getExtendedState().getVariables().get("machineId");
|
||||
System.err.println(String.format("[%s] 状态机错误: %s, 异常: %s",
|
||||
getName(), machineId, exception.getMessage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extendedStateChanged(Object key, Object value) {
|
||||
System.out.println(String.format("[%s] 扩展状态变化: %s = %s", getName(), key, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateContext(StateContext<DrcState, DrcEvent> stateContext) {
|
||||
// 默认不处理
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.tuoheng.status.machine.repository.AirportPlatformRepository;
|
|||
import com.tuoheng.status.machine.platform.strategy.AirportPlatformStrategy;
|
||||
import com.tuoheng.status.machine.platform.strategy.CoverPlatformStrategy;
|
||||
import com.tuoheng.status.machine.platform.strategy.DronePlatformStrategy;
|
||||
import com.tuoheng.status.machine.platform.strategy.DrcPlatformStrategy;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
|
@ -44,6 +45,13 @@ public class PlatformStrategyFactory {
|
|||
*/
|
||||
private final Map<PlatformType, DronePlatformStrategy> droneStrategyMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 存储所有DRC平台策略实现
|
||||
* Key: PlatformType
|
||||
* Value: DrcPlatformStrategy实现
|
||||
*/
|
||||
private final Map<PlatformType, DrcPlatformStrategy> drcStrategyMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 存储各平台对应的系统管理器实现
|
||||
* Key: PlatformType
|
||||
|
|
@ -53,13 +61,14 @@ public class PlatformStrategyFactory {
|
|||
|
||||
/**
|
||||
* 注册所有平台策略
|
||||
* Spring会自动注入所有实现了AirportPlatformStrategy、CoverPlatformStrategy和DronePlatformStrategy的Bean
|
||||
* Spring会自动注入所有实现了AirportPlatformStrategy、CoverPlatformStrategy、DronePlatformStrategy和DrcPlatformStrategy的Bean
|
||||
*/
|
||||
@Autowired
|
||||
public void registerStrategies(
|
||||
List<AirportPlatformStrategy> airportStrategies,
|
||||
List<CoverPlatformStrategy> coverStrategies,
|
||||
List<DronePlatformStrategy> droneStrategies,
|
||||
List<DrcPlatformStrategy> drcStrategies,
|
||||
List<AirportSystemManager> systemManagers) {
|
||||
|
||||
// 注册机巢策略
|
||||
|
|
@ -83,6 +92,13 @@ public class PlatformStrategyFactory {
|
|||
strategy.getPlatformType().getName(), strategy.getClass().getSimpleName()));
|
||||
}
|
||||
|
||||
// 注册DRC策略
|
||||
for (DrcPlatformStrategy strategy : drcStrategies) {
|
||||
drcStrategyMap.put(strategy.getPlatformType(), strategy);
|
||||
System.out.println(String.format("注册DRC平台策略: %s -> %s",
|
||||
strategy.getPlatformType().getName(), strategy.getClass().getSimpleName()));
|
||||
}
|
||||
|
||||
// 注册系统管理器
|
||||
for (AirportSystemManager manager : systemManagers) {
|
||||
managerMap.put(manager.getPlatformType(), manager);
|
||||
|
|
@ -223,6 +239,42 @@ public class PlatformStrategyFactory {
|
|||
return droneStrategyMap.get(platformType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据机巢SN获取DRC平台策略
|
||||
*
|
||||
* @param airportSn 机巢序列号
|
||||
* @return DRC平台策略
|
||||
* @throws IllegalArgumentException 如果机巢未注册或平台策略不存在
|
||||
*/
|
||||
public DrcPlatformStrategy getDrcStrategy(String airportSn) {
|
||||
// 从数据库查询平台类型
|
||||
PlatformType platformType = airportPlatformRepository.getPlatformType(airportSn);
|
||||
|
||||
if (platformType == null) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("机巢未注册或平台类型未配置: %s", airportSn));
|
||||
}
|
||||
|
||||
DrcPlatformStrategy strategy = drcStrategyMap.get(platformType);
|
||||
|
||||
if (strategy == null) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("未找到DRC平台策略: %s (机巢: %s)", platformType.getName(), airportSn));
|
||||
}
|
||||
|
||||
return strategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据平台类型获取DRC平台策略
|
||||
*
|
||||
* @param platformType 平台类型
|
||||
* @return DRC平台策略
|
||||
*/
|
||||
public DrcPlatformStrategy getDrcStrategyByType(PlatformType platformType) {
|
||||
return drcStrategyMap.get(platformType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取机巢的平台类型
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
package com.tuoheng.status.machine.platform.impl.dji;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.platform.PlatformType;
|
||||
import com.tuoheng.status.machine.platform.impl.dji.action.drc.*;
|
||||
import com.tuoheng.status.machine.platform.impl.dji.guard.drc.*;
|
||||
import com.tuoheng.status.machine.platform.impl.dji.listener.DjiDrcListener;
|
||||
import com.tuoheng.status.machine.platform.strategy.DrcPlatformStrategy;
|
||||
import com.tuoheng.status.machine.platform.strategy.PlatformAction;
|
||||
import com.tuoheng.status.machine.platform.strategy.PlatformGuard;
|
||||
import com.tuoheng.status.machine.platform.strategy.PlatformListener;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* DJI平台DRC策略实现
|
||||
*/
|
||||
@Component
|
||||
public class DjiDrcPlatformStrategy implements DrcPlatformStrategy {
|
||||
|
||||
@Autowired
|
||||
private DjiCanEnterGuard canEnterGuard;
|
||||
|
||||
@Autowired
|
||||
private DjiCanExitGuard canExitGuard;
|
||||
|
||||
@Autowired
|
||||
private DjiEnterAction enterAction;
|
||||
|
||||
@Autowired
|
||||
private DjiEnteredAction enteredAction;
|
||||
|
||||
@Autowired
|
||||
private DjiExitAction exitAction;
|
||||
|
||||
@Autowired
|
||||
private DjiExitedAction exitedAction;
|
||||
|
||||
@Autowired
|
||||
private DjiDrcListener djiDrcListener;
|
||||
|
||||
@Override
|
||||
public PlatformType getPlatformType() {
|
||||
return PlatformType.DJI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformGuard<DrcState, DrcEvent> getCanEnterGuard() {
|
||||
return canEnterGuard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformGuard<DrcState, DrcEvent> getCanExitGuard() {
|
||||
return canExitGuard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformAction<DrcState, DrcEvent> getEnterAction() {
|
||||
return enterAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformAction<DrcState, DrcEvent> getEnteredAction() {
|
||||
return enteredAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformAction<DrcState, DrcEvent> getExitAction() {
|
||||
return exitAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformAction<DrcState, DrcEvent> getExitedAction() {
|
||||
return exitedAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformListener<DrcState, DrcEvent> getListener() {
|
||||
return djiDrcListener;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tuoheng.status.machine.platform.impl.dji.action.drc;
|
||||
|
||||
import com.tuoheng.status.machine.action.drc.EnterAction;
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class DjiEnterAction extends EnterAction {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "DjiEnterAction";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<DrcState, DrcEvent> context) {
|
||||
String machineId = (String) context.getExtendedState().getVariables().get("machineId");
|
||||
System.out.println(String.format("[DJI] 进入DRC模式: %s", machineId));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tuoheng.status.machine.platform.impl.dji.action.drc;
|
||||
|
||||
import com.tuoheng.status.machine.action.drc.EnteredAction;
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class DjiEnteredAction extends EnteredAction {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "DjiEnteredAction";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<DrcState, DrcEvent> context) {
|
||||
String machineId = (String) context.getExtendedState().getVariables().get("machineId");
|
||||
System.out.println(String.format("[DJI] 已进入DRC模式: %s", machineId));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tuoheng.status.machine.platform.impl.dji.action.drc;
|
||||
|
||||
import com.tuoheng.status.machine.action.drc.ExitAction;
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class DjiExitAction extends ExitAction {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "DjiExitAction";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<DrcState, DrcEvent> context) {
|
||||
String machineId = (String) context.getExtendedState().getVariables().get("machineId");
|
||||
System.out.println(String.format("[DJI] 退出DRC模式: %s", machineId));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tuoheng.status.machine.platform.impl.dji.action.drc;
|
||||
|
||||
import com.tuoheng.status.machine.action.drc.ExitedAction;
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class DjiExitedAction extends ExitedAction {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "DjiExitedAction";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(StateContext<DrcState, DrcEvent> context) {
|
||||
String machineId = (String) context.getExtendedState().getVariables().get("machineId");
|
||||
System.out.println(String.format("[DJI] 已退出DRC模式: %s", machineId));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tuoheng.status.machine.platform.impl.dji.guard.drc;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.guard.drc.CanEnterGuard;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* DJI平台:检查是否可以进入DRC模式
|
||||
*/
|
||||
@Component
|
||||
public class DjiCanEnterGuard extends CanEnterGuard {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "DjiCanEnterGuard";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(StateContext<DrcState, DrcEvent> context) {
|
||||
// DJI平台特定的进入DRC模式检查逻辑
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tuoheng.status.machine.platform.impl.dji.guard.drc;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.guard.drc.CanExitGuard;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* DJI平台:检查是否可以退出DRC模式
|
||||
*/
|
||||
@Component
|
||||
public class DjiCanExitGuard extends CanExitGuard {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "DjiCanExitGuard";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(StateContext<DrcState, DrcEvent> context) {
|
||||
// DJI平台特定的退出DRC模式检查逻辑
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tuoheng.status.machine.platform.impl.dji.listener;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.listener.DefaultDrcListener;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* DJI平台DRC状态监听器
|
||||
*/
|
||||
@Component
|
||||
public class DjiDrcListener extends DefaultDrcListener {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "DJI-DRC";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package com.tuoheng.status.machine.platform.strategy;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.platform.PlatformType;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
|
||||
/**
|
||||
* DRC(飞行控制模式)平台策略接口
|
||||
* 定义各平台需要实现的Guard、Action和Listener
|
||||
*/
|
||||
public interface DrcPlatformStrategy {
|
||||
|
||||
/**
|
||||
* 获取平台类型
|
||||
*/
|
||||
PlatformType getPlatformType();
|
||||
|
||||
// ==================== Guards ====================
|
||||
|
||||
/**
|
||||
* 是否可以进入DRC模式
|
||||
*/
|
||||
PlatformGuard<DrcState, DrcEvent> getCanEnterGuard();
|
||||
|
||||
/**
|
||||
* 是否可以退出DRC模式
|
||||
*/
|
||||
PlatformGuard<DrcState, DrcEvent> getCanExitGuard();
|
||||
|
||||
// ==================== Actions ====================
|
||||
|
||||
/**
|
||||
* 进入DRC模式动作
|
||||
*/
|
||||
PlatformAction<DrcState, DrcEvent> getEnterAction();
|
||||
|
||||
/**
|
||||
* 进入DRC模式完成动作
|
||||
*/
|
||||
PlatformAction<DrcState, DrcEvent> getEnteredAction();
|
||||
|
||||
/**
|
||||
* 退出DRC模式动作
|
||||
*/
|
||||
PlatformAction<DrcState, DrcEvent> getExitAction();
|
||||
|
||||
/**
|
||||
* 退出DRC模式完成动作
|
||||
*/
|
||||
PlatformAction<DrcState, DrcEvent> getExitedAction();
|
||||
|
||||
// ==================== Listener ====================
|
||||
|
||||
/**
|
||||
* 获取平台Listener
|
||||
* 每个平台有一个Listener实例,所有该平台的DRC共享
|
||||
*/
|
||||
PlatformListener<DrcState, DrcEvent> getListener();
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package com.tuoheng.status.machine.redis;
|
|||
import com.tuoheng.status.machine.status.AirportState;
|
||||
import com.tuoheng.status.machine.status.CoverState;
|
||||
import com.tuoheng.status.machine.status.DroneState;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
|
@ -11,7 +12,7 @@ import java.util.Set;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 使用 Redis 记录和恢复机巢/舱门/无人机状态的存储组件。
|
||||
* 使用 Redis 记录和恢复机巢/舱门/无人机/DRC状态的存储组件。
|
||||
*
|
||||
* 当前实现采用内存 Map 占位,便于无 Redis 环境下直接运行。
|
||||
* 如果接入真正的 Redis,只需将存取逻辑替换为 RedisTemplate 等实现。
|
||||
|
|
@ -22,6 +23,7 @@ public class RedisStateStore {
|
|||
private final Map<String, AirportState> airportStateMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, CoverState> coverStateMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, DroneState> droneStateMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, DrcState> drcStateMap = new ConcurrentHashMap<>();
|
||||
|
||||
public void saveAirportState(String airportSn, AirportState state) {
|
||||
if (airportSn != null && state != null) {
|
||||
|
|
@ -41,6 +43,12 @@ public class RedisStateStore {
|
|||
}
|
||||
}
|
||||
|
||||
public void saveDrcState(String airportSn, DrcState state) {
|
||||
if (airportSn != null && state != null) {
|
||||
drcStateMap.put(airportSn, state);
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<AirportState> loadAirportState(String airportSn) {
|
||||
return Optional.ofNullable(airportStateMap.get(airportSn));
|
||||
}
|
||||
|
|
@ -53,6 +61,10 @@ public class RedisStateStore {
|
|||
return Optional.ofNullable(droneStateMap.get(droneSn));
|
||||
}
|
||||
|
||||
public Optional<DrcState> loadDrcState(String airportSn) {
|
||||
return Optional.ofNullable(drcStateMap.get(airportSn));
|
||||
}
|
||||
|
||||
public Set<String> allAirportIds() {
|
||||
// 合并两张表的 key,防止有只存机场或只存舱门的情况
|
||||
Set<String> ids = ConcurrentHashMap.newKeySet();
|
||||
|
|
@ -64,5 +76,9 @@ public class RedisStateStore {
|
|||
public Set<String> allDroneIds() {
|
||||
return droneStateMap.keySet();
|
||||
}
|
||||
|
||||
public Set<String> allDrcIds() {
|
||||
return drcStateMap.keySet();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,191 @@
|
|||
package com.tuoheng.status.machine.service;
|
||||
|
||||
import com.tuoheng.status.machine.events.DrcEvent;
|
||||
import com.tuoheng.status.machine.redis.RedisStateStore;
|
||||
import com.tuoheng.status.machine.status.DrcState;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.config.StateMachineFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* DRC状态机管理器
|
||||
* 负责管理多个机巢的DRC状态机实例
|
||||
*/
|
||||
@Component
|
||||
public class DrcMachineService {
|
||||
|
||||
@Autowired
|
||||
StateMachineFactory<DrcState, DrcEvent> drcStateMachineFactory;
|
||||
|
||||
@Autowired
|
||||
private RedisStateStore redisStateStore;
|
||||
|
||||
/**
|
||||
* 存储所有机巢的DRC状态机实例
|
||||
* Key: 机巢ID (airportSn)
|
||||
* Value: 状态机实例
|
||||
*/
|
||||
private final Map<String, StateMachine<DrcState, DrcEvent>> stateMachineMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 获取或创建状态机
|
||||
* 如果状态机不存在,则创建新的状态机实例
|
||||
*
|
||||
* @param airportSn 机巢序列号
|
||||
* @return 状态机实例
|
||||
*/
|
||||
public StateMachine<DrcState, DrcEvent> getOrCreateStateMachine(String airportSn) {
|
||||
return stateMachineMap.computeIfAbsent(airportSn, id -> {
|
||||
StateMachine<DrcState, DrcEvent> stateMachine = drcStateMachineFactory.getStateMachine(id);
|
||||
// 服务器重启后,状态机初始化为 UNKNOWN 状态
|
||||
// 不从 Redis 恢复旧状态,等待第一次心跳同步真实状态
|
||||
// 这样可以避免服务器重启期间丢失心跳导致的状态不一致问题
|
||||
stateMachine.start();
|
||||
System.out.println(String.format("创建并启动DRC状态机: %s, 初始状态: UNKNOWN (等待心跳同步)", id));
|
||||
return stateMachine;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态机(不创建)
|
||||
*
|
||||
* @param airportSn 机巢序列号
|
||||
* @return 状态机实例,如果不存在返回null
|
||||
*/
|
||||
public StateMachine<DrcState, DrcEvent> getStateMachine(String airportSn) {
|
||||
return stateMachineMap.get(airportSn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态机的当前状态
|
||||
*
|
||||
* @param airportSn 机巢序列号
|
||||
* @return 当前状态,如果状态机不存在返回null
|
||||
*/
|
||||
public DrcState getCurrentState(String airportSn) {
|
||||
StateMachine<DrcState, DrcEvent> stateMachine = stateMachineMap.get(airportSn);
|
||||
if (stateMachine == null) {
|
||||
System.out.println("DRC状态机不存在: " + airportSn);
|
||||
return null;
|
||||
}
|
||||
return stateMachine.getState().getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态机的所有当前状态(包括子状态)
|
||||
*
|
||||
* @param airportSn 机巢序列号
|
||||
* @return 当前状态集合的字符串表示
|
||||
*/
|
||||
public String getCurrentStates(String airportSn) {
|
||||
StateMachine<DrcState, DrcEvent> stateMachine = stateMachineMap.get(airportSn);
|
||||
if (stateMachine == null) {
|
||||
return "状态机不存在";
|
||||
}
|
||||
|
||||
StringBuilder states = new StringBuilder();
|
||||
stateMachine.getState().getIds().forEach(state -> {
|
||||
if (states.length() > 0) {
|
||||
states.append(" -> ");
|
||||
}
|
||||
states.append(state);
|
||||
});
|
||||
|
||||
return states.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送事件到状态机
|
||||
*
|
||||
* @param airportSn 机巢序列号
|
||||
* @param event 事件
|
||||
* @return 是否发送成功
|
||||
*/
|
||||
public boolean sendEvent(String airportSn, DrcEvent event) {
|
||||
StateMachine<DrcState, DrcEvent> stateMachine = getOrCreateStateMachine(airportSn);
|
||||
boolean result = stateMachine.sendEvent(event);
|
||||
|
||||
if (result) {
|
||||
// 持久化最新状态
|
||||
redisStateStore.saveDrcState(airportSn, stateMachine.getState().getId());
|
||||
System.out.println(String.format("DRC事件发送成功 - 机巢: %s, 事件: %s, 当前状态: %s",
|
||||
airportSn, event, getCurrentStates(airportSn)));
|
||||
} else {
|
||||
System.out.println(String.format("DRC事件发送失败 - 机巢: %s, 事件: %s, 当前状态: %s",
|
||||
airportSn, event, getCurrentStates(airportSn)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除状态机
|
||||
*
|
||||
* @param airportSn 机巢序列号
|
||||
*/
|
||||
public void removeStateMachine(String airportSn) {
|
||||
StateMachine<DrcState, DrcEvent> stateMachine = stateMachineMap.remove(airportSn);
|
||||
if (stateMachine != null) {
|
||||
stateMachine.stop();
|
||||
System.out.println("停止并移除DRC状态机: " + airportSn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查状态机是否存在
|
||||
*
|
||||
* @param airportSn 机巢序列号
|
||||
* @return 是否存在
|
||||
*/
|
||||
public boolean hasStateMachine(String airportSn) {
|
||||
return stateMachineMap.containsKey(airportSn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有状态机的数量
|
||||
*
|
||||
* @return 状态机数量
|
||||
*/
|
||||
public int getStateMachineCount() {
|
||||
return stateMachineMap.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有机巢ID
|
||||
*
|
||||
* @return 机巢ID集合
|
||||
*/
|
||||
public java.util.Set<String> getAllAirportIds() {
|
||||
return stateMachineMap.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查状态机是否处于指定状态
|
||||
*
|
||||
* @param airportSn 机巢序列号
|
||||
* @param state 要检查的状态
|
||||
* @return 是否处于指定状态
|
||||
*/
|
||||
public boolean isInState(String airportSn, DrcState state) {
|
||||
StateMachine<DrcState, DrcEvent> stateMachine = stateMachineMap.get(airportSn);
|
||||
if (stateMachine == null) {
|
||||
return false;
|
||||
}
|
||||
return stateMachine.getState().getIds().contains(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重启状态机
|
||||
*
|
||||
* @param airportSn 机巢序列号
|
||||
*/
|
||||
public void restartStateMachine(String airportSn) {
|
||||
removeStateMachine(airportSn);
|
||||
getOrCreateStateMachine(airportSn);
|
||||
System.out.println("重启DRC状态机: " + airportSn);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,5 +5,28 @@ package com.tuoheng.status.machine.status;
|
|||
* 未知状态 退出状态 进入中 进入状态 退出中
|
||||
*/
|
||||
public enum DrcState {
|
||||
/**
|
||||
* 未知状态(服务器重启后的初始状态,等待第一次心跳同步)
|
||||
*/
|
||||
UNKNOWN,
|
||||
|
||||
/**
|
||||
* 退出状态(DRC模式已退出)
|
||||
*/
|
||||
EXITED,
|
||||
|
||||
/**
|
||||
* 进入中(正在进入DRC模式)
|
||||
*/
|
||||
ENTERING,
|
||||
|
||||
/**
|
||||
* 进入状态(已进入DRC模式)
|
||||
*/
|
||||
ENTERED,
|
||||
|
||||
/**
|
||||
* 退出中(正在退出DRC模式)
|
||||
*/
|
||||
EXITING
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue