187 lines
7.3 KiB
Python
187 lines
7.3 KiB
Python
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
"""
|
|||
|
|
装备模型生命周期状态机
|
|||
|
|
─────────────────────────────────────────────────────────────────
|
|||
|
|
LifecycleState 枚举:CREATED / READY / RUNNING / PAUSED /
|
|||
|
|
STOPPED / ERROR
|
|||
|
|
LifecycleFSM 有限状态机:管理合法状态转移,非法转移抛出异常
|
|||
|
|
─────────────────────────────────────────────────────────────────
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
from enum import Enum
|
|||
|
|
from typing import Dict, Set, Callable, Optional
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────────────────────────
|
|||
|
|
# 生命周期状态枚举
|
|||
|
|
# ─────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
class LifecycleState(Enum):
|
|||
|
|
CREATED = "CREATED" # 刚创建,参数未就绪
|
|||
|
|
READY = "READY" # 参数就绪,可启动
|
|||
|
|
RUNNING = "RUNNING" # 仿真运行中
|
|||
|
|
PAUSED = "PAUSED" # 暂停(可恢复)
|
|||
|
|
STOPPED = "STOPPED" # 已停止(不可恢复,需 reset)
|
|||
|
|
ERROR = "ERROR" # 发生错误
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────────────────────────
|
|||
|
|
# 合法状态转移表
|
|||
|
|
# ─────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
# { 当前状态 → 可转移到的目标状态集合 }
|
|||
|
|
_TRANSITIONS: Dict[LifecycleState, Set[LifecycleState]] = {
|
|||
|
|
LifecycleState.CREATED: {
|
|||
|
|
LifecycleState.READY,
|
|||
|
|
LifecycleState.ERROR,
|
|||
|
|
},
|
|||
|
|
LifecycleState.READY: {
|
|||
|
|
LifecycleState.RUNNING,
|
|||
|
|
LifecycleState.ERROR,
|
|||
|
|
},
|
|||
|
|
LifecycleState.RUNNING: {
|
|||
|
|
LifecycleState.PAUSED,
|
|||
|
|
LifecycleState.STOPPED,
|
|||
|
|
LifecycleState.ERROR,
|
|||
|
|
LifecycleState.READY, # reset 时
|
|||
|
|
},
|
|||
|
|
LifecycleState.PAUSED: {
|
|||
|
|
LifecycleState.RUNNING,
|
|||
|
|
LifecycleState.STOPPED,
|
|||
|
|
LifecycleState.ERROR,
|
|||
|
|
LifecycleState.READY, # reset 时
|
|||
|
|
},
|
|||
|
|
LifecycleState.STOPPED: {
|
|||
|
|
LifecycleState.READY, # reset 后可重新启动
|
|||
|
|
LifecycleState.ERROR,
|
|||
|
|
},
|
|||
|
|
LifecycleState.ERROR: {
|
|||
|
|
LifecycleState.READY, # 错误恢复后 reset
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────────────────────────
|
|||
|
|
# 生命周期有限状态机
|
|||
|
|
# ─────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
class LifecycleFSM:
|
|||
|
|
"""
|
|||
|
|
装备模型生命周期有限状态机
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
- 维护当前状态
|
|||
|
|
- 校验状态转移合法性
|
|||
|
|
- 触发转移回调(on_enter / on_exit)
|
|||
|
|
- 记录状态历史
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
def __init__(
|
|||
|
|
self,
|
|||
|
|
initial: LifecycleState = LifecycleState.CREATED,
|
|||
|
|
on_changed: Optional[Callable[[str, str], None]] = None,
|
|||
|
|
):
|
|||
|
|
self._state: LifecycleState = initial
|
|||
|
|
self._history: list = [(initial, 0.0)]
|
|||
|
|
self._on_changed = on_changed # (old, new) 回调
|
|||
|
|
|
|||
|
|
# ── 属性 ──────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def state(self) -> LifecycleState:
|
|||
|
|
return self._state
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def history(self) -> list:
|
|||
|
|
return list(self._history)
|
|||
|
|
|
|||
|
|
# ── 状态查询 ──────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def is_running(self) -> bool:
|
|||
|
|
return self._state == LifecycleState.RUNNING
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def is_paused(self) -> bool:
|
|||
|
|
return self._state == LifecycleState.PAUSED
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def is_stopped(self) -> bool:
|
|||
|
|
return self._state == LifecycleState.STOPPED
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def is_ready(self) -> bool:
|
|||
|
|
return self._state == LifecycleState.READY
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def is_error(self) -> bool:
|
|||
|
|
return self._state == LifecycleState.ERROR
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def can_step(self) -> bool:
|
|||
|
|
"""是否可以执行 step()"""
|
|||
|
|
return self._state == LifecycleState.RUNNING
|
|||
|
|
|
|||
|
|
# ── 状态转移 ──────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
def transition(
|
|||
|
|
self,
|
|||
|
|
target: LifecycleState,
|
|||
|
|
timestamp: float = 0.0,
|
|||
|
|
force: bool = False,
|
|||
|
|
) -> bool:
|
|||
|
|
"""
|
|||
|
|
执行状态转移
|
|||
|
|
:param target: 目标状态
|
|||
|
|
:param timestamp: 当前仿真时刻(用于历史记录)
|
|||
|
|
:param force: True=强制转移(跳过合法性检查,仅内部使用)
|
|||
|
|
:return: True=转移成功,False=已在目标状态
|
|||
|
|
:raises ValueError: 非法状态转移
|
|||
|
|
"""
|
|||
|
|
if self._state == target:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
if not force:
|
|||
|
|
allowed = _TRANSITIONS.get(self._state, set())
|
|||
|
|
if target not in allowed:
|
|||
|
|
raise ValueError(
|
|||
|
|
f"非法状态转移: {self._state.value} → {target.value} "
|
|||
|
|
f"(允许: {[s.value for s in allowed]})"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
old_state = self._state
|
|||
|
|
self._state = target
|
|||
|
|
self._history.append((target, timestamp))
|
|||
|
|
|
|||
|
|
if self._on_changed:
|
|||
|
|
self._on_changed(old_state.value, target.value)
|
|||
|
|
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# ── 快捷转移方法 ──────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
def to_ready(self, t: float = 0.0) -> bool:
|
|||
|
|
return self.transition(LifecycleState.READY, t)
|
|||
|
|
|
|||
|
|
def to_running(self, t: float = 0.0) -> bool:
|
|||
|
|
return self.transition(LifecycleState.RUNNING, t)
|
|||
|
|
|
|||
|
|
def to_paused(self, t: float = 0.0) -> bool:
|
|||
|
|
return self.transition(LifecycleState.PAUSED, t)
|
|||
|
|
|
|||
|
|
def to_stopped(self, t: float = 0.0) -> bool:
|
|||
|
|
return self.transition(LifecycleState.STOPPED, t)
|
|||
|
|
|
|||
|
|
def to_error(self, t: float = 0.0) -> bool:
|
|||
|
|
return self.transition(LifecycleState.ERROR, t, force=True)
|
|||
|
|
|
|||
|
|
# ── 工具 ──────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
def reset(self, t: float = 0.0) -> bool:
|
|||
|
|
"""强制重置到 READY(任意状态均可)"""
|
|||
|
|
return self.transition(LifecycleState.READY, t, force=True)
|
|||
|
|
|
|||
|
|
def __repr__(self) -> str:
|
|||
|
|
return f"LifecycleFSM(state={self._state.value})"
|