using System;
using Stateless;
using VM.PlatformSDKCS;
using VM.Core;
namespace HkVisionPro.App.Automation
{
///
/// 自动装配流程状态枚举。
///
public enum AutoAssemblyState
{
///
/// 空闲状态,尚未启动自动流程。
///
Idle,
///
/// A 层检测中。
///
LayerAInspecting,
///
/// B 层检测中。
///
LayerBInspecting,
///
/// C 层检测中。
///
LayerCInspecting,
///
/// 单件产品 A/B/C 全部通过。
///
ProductCompleted,
///
/// 自动流程已停止。
///
Stopped,
///
/// 自动流程故障状态。
///
Faulted,
}
///
/// 自动装配流程状态通知事件参数。
///
public sealed class AutoAssemblyStatusChangedEventArgs : EventArgs
{
///
/// 当前状态。
///
public AutoAssemblyState State { get; }
///
/// 状态说明文本。
///
public string Message { get; }
///
/// 当前产品序号(从 1 开始)。
///
public int ProductIndex { get; }
///
/// 当前激活流程名称。
///
public string ActiveProcedureName { get; }
///
/// 当前稳定计时已累计毫秒数。
///
public int StableElapsedMilliseconds { get; }
///
/// 稳定计时目标毫秒数。
///
public int StableTargetMilliseconds { get; }
///
/// 状态变化事件参数构造函数。
///
/// 当前状态。
/// 状态说明。
/// 当前产品序号(从 1 开始)。
/// 当前流程名称。
/// 当前稳定计时累计毫秒数。
/// 稳定计时目标毫秒数。
public AutoAssemblyStatusChangedEventArgs(
AutoAssemblyState state,
string message,
int productIndex = 0,
string activeProcedureName = "",
int stableElapsedMilliseconds = 0,
int stableTargetMilliseconds = 0)
{
State = state;
Message = message ?? string.Empty;
ProductIndex = productIndex < 0 ? 0 : productIndex;
ActiveProcedureName = activeProcedureName ?? string.Empty;
StableElapsedMilliseconds = stableElapsedMilliseconds < 0 ? 0 : stableElapsedMilliseconds;
StableTargetMilliseconds = stableTargetMilliseconds < 0 ? 0 : stableTargetMilliseconds;
}
}
///
/// 自动装配流程配置参数。
///
public sealed class AutoAssemblyOptions
{
///
/// A 层流程名称。
///
public string ProcedureAName { get; set; }
///
/// B 层流程名称。
///
public string ProcedureBName { get; set; }
///
/// C 层流程名称。
///
public string ProcedureCName { get; set; }
///
/// 判定 OK 的整型输出名。
///
public string OkIntOutputName { get; set; }
///
/// 判定 OK 的第二个整型输出名(当配置后,需与第一个整型输出同时满足目标值才判定为 OK)。
///
public string OkIntOutputName2 { get; set; }
///
/// 判定 OK 的整型目标值。
///
public int OkIntValue { get; set; }
///
/// OK 持续稳定时间(毫秒)。
///
public int StableOkMilliseconds { get; set; }
///
/// 校验配置参数有效性。
///
public void Validate()
{
if (string.IsNullOrWhiteSpace(ProcedureAName) || string.IsNullOrWhiteSpace(ProcedureBName) || string.IsNullOrWhiteSpace(ProcedureCName))
{
throw new ArgumentException("自动装配流程名称配置无效,请检查 A/B/C 流程名称。", nameof(AutoAssemblyOptions));
}
if (string.IsNullOrWhiteSpace(OkIntOutputName) || string.IsNullOrWhiteSpace(OkIntOutputName2))
{
throw new ArgumentException("自动装配判定输出配置无效,请检查 Result1/Result2 输出名称。", nameof(AutoAssemblyOptions));
}
if (StableOkMilliseconds <= 0)
{
throw new ArgumentOutOfRangeException(nameof(StableOkMilliseconds), "稳定判定时长必须大于 0。");
}
}
}
///
/// 自动装配流程状态机触发器。
///
internal enum AutoAssemblyTrigger
{
///
/// 启动自动流程。
///
Start,
///
/// 当前层流程结果持续 OK 达标。
///
StableOkReached,
///
/// 停止自动流程。
///
Stop,
///
/// 单件产品完成后进入下一件。
///
NextProduct,
///
/// 自动流程异常。
///
Fault,
}
///
/// 自动装配流程控制器:
/// 基于 Stateless 状态机实现 A -> B -> C 顺序检测,并以“连续 OK 达标时长”驱动层间切换。
///
public sealed class AutoAssemblyWorkflowController : IDisposable
{
///
/// 并发互斥锁。
///
private readonly object _syncRoot = new object();
///
/// 自动流程配置。
///
private readonly AutoAssemblyOptions _options;
///
/// 日志输出委托。
///
private readonly Action _logger;
///
/// 外部渲染回调(可选)。
///
private readonly Action _renderResultAction;
///
/// Stateless 状态机。
///
private readonly StateMachine _stateMachine;
///
/// 当前激活流程。
///
private VmProcedure _activeProcedure;
///
/// 当前流程首次出现 OK 的起始时间(UTC)。
///
private DateTime _okBeginUtc;
///
/// 当前是否处于 OK 稳定计时中。
///
private bool _isOkTiming;
///
/// 控制器是否处于运行中。
///
private bool _isRunning;
///
/// 控制器是否已释放。
///
private bool _isDisposed;
///
/// 最近一次“输出缺失”日志时间(用于限流)。
///
private DateTime _lastMissingOutputLogUtc;
///
/// 最近一次稳定计时进度上报时间(用于限流)。
///
private DateTime _lastStableProgressReportUtc;
///
/// VisionMaster: 模块已处于连续执行中的错误码(IMVS_EC_MODULE_CONTINUE_EXECUTE)。
///
private const int VmErrorCodeModuleContinueExecute = -536870127;
///
/// 当前产品序号(从 1 开始)。
///
private int _currentProductIndex;
///
/// 状态变化事件。
///
public event EventHandler StatusChanged;
///
/// 当前状态。
///
public AutoAssemblyState CurrentState => _stateMachine.State;
///
/// 是否正在自动运行。
///
public bool IsRunning => _isRunning;
///
/// 自动装配流程控制器构造函数。
///
/// 自动流程参数。
/// 日志输出委托(可为空)。
/// 渲染回调(可为空)。
public AutoAssemblyWorkflowController(
AutoAssemblyOptions options,
Action logger,
Action renderResultAction)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
_options.Validate();
_logger = logger;
_renderResultAction = renderResultAction;
_okBeginUtc = DateTime.MinValue;
_lastMissingOutputLogUtc = DateTime.MinValue;
_lastStableProgressReportUtc = DateTime.MinValue;
_currentProductIndex = 1;
_stateMachine = new StateMachine(AutoAssemblyState.Idle);
ConfigureStateMachine();
}
///
/// 启动自动装配流程。
///
public void Start()
{
lock (_syncRoot)
{
ThrowIfDisposed();
if (_isRunning)
{
return;
}
_currentProductIndex = 1;
_okBeginUtc = DateTime.MinValue;
_isOkTiming = false;
_lastStableProgressReportUtc = DateTime.MinValue;
_isRunning = true;
try
{
FireIfPermitted(AutoAssemblyTrigger.Start);
}
catch
{
// 启动阶段若状态机进入失败,需回滚运行状态,避免外部误判“已运行”。
_isRunning = false;
DeactivateCurrentProcedure("启动失败回滚");
throw;
}
}
}
///
/// 停止自动装配流程。
///
/// 停止原因。
public void Stop(string reason)
{
lock (_syncRoot)
{
if (_isDisposed)
{
return;
}
if (!_isRunning)
{
return;
}
FireIfPermitted(AutoAssemblyTrigger.Stop);
_isRunning = false;
PublishStatus(AutoAssemblyState.Stopped, $"自动流程停止:{reason}");
}
}
///
/// 释放控制器资源。
///
public void Dispose()
{
lock (_syncRoot)
{
if (_isDisposed)
{
return;
}
try
{
Stop("控制器释放");
DeactivateCurrentProcedure("控制器释放");
}
finally
{
_isDisposed = true;
}
}
}
///
/// 配置状态机。
///
private void ConfigureStateMachine()
{
_stateMachine.Configure(AutoAssemblyState.Idle)
.Permit(AutoAssemblyTrigger.Start, AutoAssemblyState.LayerAInspecting)
.Permit(AutoAssemblyTrigger.Stop, AutoAssemblyState.Stopped);
ConfigureLayerState(AutoAssemblyState.LayerAInspecting, _options.ProcedureAName, "A层", AutoAssemblyState.LayerBInspecting);
ConfigureLayerState(AutoAssemblyState.LayerBInspecting, _options.ProcedureBName, "B层", AutoAssemblyState.LayerCInspecting);
ConfigureLayerState(AutoAssemblyState.LayerCInspecting, _options.ProcedureCName, "C层", AutoAssemblyState.ProductCompleted);
_stateMachine.Configure(AutoAssemblyState.ProductCompleted)
.OnEntry(() =>
{
PublishStatus(AutoAssemblyState.ProductCompleted, "整机检测结果:OK,进入下一产品。");
_currentProductIndex++;
if (_isRunning)
{
FireIfPermitted(AutoAssemblyTrigger.NextProduct);
}
})
.Permit(AutoAssemblyTrigger.NextProduct, AutoAssemblyState.LayerAInspecting)
.Permit(AutoAssemblyTrigger.Stop, AutoAssemblyState.Stopped)
.Permit(AutoAssemblyTrigger.Fault, AutoAssemblyState.Faulted);
_stateMachine.Configure(AutoAssemblyState.Stopped)
.OnEntry(() =>
{
_isRunning = false;
DeactivateCurrentProcedure("状态机停止");
})
.Permit(AutoAssemblyTrigger.Start, AutoAssemblyState.LayerAInspecting);
_stateMachine.Configure(AutoAssemblyState.Faulted)
.OnEntry(() =>
{
_isRunning = false;
DeactivateCurrentProcedure("状态机故障");
PublishStatus(AutoAssemblyState.Faulted, "自动流程发生异常,已停止。");
})
.Permit(AutoAssemblyTrigger.Start, AutoAssemblyState.LayerAInspecting)
.Permit(AutoAssemblyTrigger.Stop, AutoAssemblyState.Stopped);
}
///
/// 配置层级检测状态。
///
/// 状态机状态。
/// 流程名称。
/// 层级显示名。
/// 连续 OK 达标后的下一状态。
private void ConfigureLayerState(
AutoAssemblyState state,
string procedureName,
string layerDisplayName,
AutoAssemblyState nextState)
{
_stateMachine.Configure(state)
.OnEntry(() => ActivateLayerProcedure(state, procedureName, layerDisplayName))
.OnExit(() => DeactivateCurrentProcedure($"离开{layerDisplayName}检测"))
.Permit(AutoAssemblyTrigger.StableOkReached, nextState)
.Permit(AutoAssemblyTrigger.Stop, AutoAssemblyState.Stopped)
.Permit(AutoAssemblyTrigger.Fault, AutoAssemblyState.Faulted);
}
///
/// 进入层级检测状态时激活对应流程。
///
/// 目标状态。
/// 流程名称。
/// 层级显示名。
private void ActivateLayerProcedure(AutoAssemblyState state, string procedureName, string layerDisplayName)
{
if (string.IsNullOrWhiteSpace(procedureName))
{
throw new InvalidOperationException($"{layerDisplayName}流程名称为空,无法启动自动检测。");
}
DeactivateCurrentProcedure($"切换到{layerDisplayName}");
var procedure = VmSolution.Instance[procedureName] as VmProcedure;
if (procedure == null)
{
throw new InvalidOperationException($"未找到自动流程:{procedureName}({layerDisplayName})。");
}
_activeProcedure = procedure;
_okBeginUtc = DateTime.MinValue;
_isOkTiming = false;
_lastStableProgressReportUtc = DateTime.MinValue;
_activeProcedure.OnWorkEndStatusCallBack -= ActiveProcedure_OnWorkEndStatusCallBack;
_activeProcedure.OnWorkEndStatusCallBack += ActiveProcedure_OnWorkEndStatusCallBack;
_activeProcedure.ContinuousRunEnable = true;
try
{
_activeProcedure.Run();
}
catch (Exception ex)
{
if (IsModuleContinueExecuteVmException(ex))
{
WriteLog($"自动流程[{procedureName}]已处于连续执行状态,沿用现有执行链路。\n若需重启请先停止当前连续执行。");
}
else
{
throw;
}
}
PublishStatus(state, $"{layerDisplayName}检测中(连续OK保持{_options.StableOkMilliseconds}ms后切换)。");
WriteLog($"自动流程切换到{layerDisplayName}:{procedureName}");
}
///
/// 关闭当前激活流程并解绑回调。
///
/// 关闭原因。
private void DeactivateCurrentProcedure(string reason)
{
if (_activeProcedure == null)
{
_okBeginUtc = DateTime.MinValue;
_isOkTiming = false;
_lastStableProgressReportUtc = DateTime.MinValue;
return;
}
try
{
_activeProcedure.OnWorkEndStatusCallBack -= ActiveProcedure_OnWorkEndStatusCallBack;
_activeProcedure.ContinuousRunEnable = false;
WriteLog($"自动流程停用:{_activeProcedure.Name}({reason})");
}
catch (Exception ex)
{
WriteLog($"停用自动流程异常:{ex.Message}");
}
finally
{
_activeProcedure = null;
_okBeginUtc = DateTime.MinValue;
_isOkTiming = false;
_lastStableProgressReportUtc = DateTime.MinValue;
}
}
///
/// 流程执行结束回调:用于判定 OK 稳定时长,并驱动状态机切换。
///
/// 回调事件源。
/// 标准事件参数。
private void ActiveProcedure_OnWorkEndStatusCallBack(object sender, EventArgs e)
{
lock (_syncRoot)
{
if (_isDisposed || !_isRunning)
{
return;
}
var procedure = sender as VmProcedure;
if (procedure == null || !ReferenceEquals(procedure, _activeProcedure))
{
return;
}
try
{
_renderResultAction?.Invoke(procedure, $"自动流程[{GetStateDisplayText(_stateMachine.State)}]");
var isOk = EvaluateProcedureResultIsOk(procedure, out var sourceName, out var sourceValue);
if (!isOk)
{
if (_isOkTiming)
{
_isOkTiming = false;
_okBeginUtc = DateTime.MinValue;
_lastStableProgressReportUtc = DateTime.MinValue;
PublishStatus(_stateMachine.State, $"{GetStateDisplayText(_stateMachine.State)}检测 NG({sourceName}={sourceValue}),继续等待。");
}
return;
}
if (!_isOkTiming)
{
_isOkTiming = true;
_okBeginUtc = DateTime.UtcNow;
_lastStableProgressReportUtc = DateTime.UtcNow;
PublishStatus(_stateMachine.State, $"{GetStateDisplayText(_stateMachine.State)}检测 OK,开始稳定计时:0/{_options.StableOkMilliseconds}ms。");
return;
}
var elapsedMs = (DateTime.UtcNow - _okBeginUtc).TotalMilliseconds;
if (elapsedMs < _options.StableOkMilliseconds)
{
if ((DateTime.UtcNow - _lastStableProgressReportUtc).TotalMilliseconds >= 500)
{
_lastStableProgressReportUtc = DateTime.UtcNow;
var currentMs = (int)Math.Max(0, elapsedMs);
PublishStatus(
_stateMachine.State,
$"{GetStateDisplayText(_stateMachine.State)}检测 OK,稳定计时:{currentMs}/{_options.StableOkMilliseconds}ms。",
false);
}
return;
}
_isOkTiming = false;
_okBeginUtc = DateTime.MinValue;
_lastStableProgressReportUtc = DateTime.MinValue;
PublishStatus(_stateMachine.State, $"{GetStateDisplayText(_stateMachine.State)}检测连续 OK 达标,准备切换下一层。");
FireIfPermitted(AutoAssemblyTrigger.StableOkReached);
}
catch (Exception ex)
{
WriteLog($"自动流程回调异常:{ex.Message}");
FireIfPermitted(AutoAssemblyTrigger.Fault);
}
}
}
///
/// 判定当前流程结果是否为 OK。
/// 判定规则:Result1 和 Result2 两个整型输出都等于目标值,才判定为 OK。
///
/// 流程对象。
/// 命中的输出名。
/// 命中的输出值。
/// 是否判定为 OK。
private bool EvaluateProcedureResultIsOk(VmProcedure procedure, out string sourceName, out string sourceValue)
{
sourceName = string.Empty;
sourceValue = string.Empty;
if (procedure == null)
{
return false;
}
var hasFirstInt = TryReadOutputInt(procedure, _options.OkIntOutputName, out var firstIntValue);
var secondIntValue = 0;
var hasSecondInt = TryReadOutputInt(procedure, _options.OkIntOutputName2, out secondIntValue);
sourceName = $"{_options.OkIntOutputName}/{_options.OkIntOutputName2}";
sourceValue = $"{(hasFirstInt ? firstIntValue.ToString() : "")}/{(hasSecondInt ? secondIntValue.ToString() : "")}";
if (hasFirstInt && hasSecondInt)
{
return firstIntValue == _options.OkIntValue && secondIntValue == _options.OkIntValue;
}
if ((DateTime.UtcNow - _lastMissingOutputLogUtc).TotalSeconds >= 5)
{
_lastMissingOutputLogUtc = DateTime.UtcNow;
WriteLog($"自动流程未读到判定输出,已尝试 Int[{_options.OkIntOutputName}/{_options.OkIntOutputName2}]。");
}
return false;
}
///
/// 尝试读取整型输出。
///
/// 流程对象。
/// 输出名。
/// 输出值。
/// 读取是否成功。
private static bool TryReadOutputInt(VmProcedure procedure, string outputName, out int value)
{
value = 0;
if (procedure == null || string.IsNullOrWhiteSpace(outputName))
{
return false;
}
try
{
var output = procedure.ModuResult.GetOutputInt(outputName);
if (output.pIntVal == null || output.pIntVal.Length == 0)
{
return false;
}
value = output.pIntVal[0];
return true;
}
catch
{
return false;
}
}
///
/// 判断异常是否为“模块已处于连续执行”错误。
///
/// 异常对象。
/// 若是连续执行中错误则返回 true。
private static bool IsModuleContinueExecuteVmException(Exception ex)
{
if (ex == null)
{
return false;
}
var vmException = VmExceptionTool.GetVmException(ex);
return vmException != null && vmException.errorCode == VmErrorCodeModuleContinueExecute;
}
///
/// 触发状态更新事件。
///
/// 状态。
/// 消息。
/// 是否写入日志。
private void PublishStatus(AutoAssemblyState state, string message, bool writeLog = true)
{
var elapsedMs = 0;
if (_isOkTiming && _okBeginUtc != DateTime.MinValue)
{
elapsedMs = (int)Math.Max(0, (DateTime.UtcNow - _okBeginUtc).TotalMilliseconds);
if (_options.StableOkMilliseconds > 0)
{
elapsedMs = Math.Min(elapsedMs, _options.StableOkMilliseconds);
}
}
var statusArgs = new AutoAssemblyStatusChangedEventArgs(
state,
message,
_currentProductIndex,
_activeProcedure?.Name ?? string.Empty,
elapsedMs,
_options.StableOkMilliseconds);
StatusChanged?.Invoke(this, statusArgs);
if (writeLog)
{
WriteLog(message);
}
}
///
/// 依据状态返回中文显示文本。
///
/// 状态枚举。
/// 中文描述。
private static string GetStateDisplayText(AutoAssemblyState state)
{
switch (state)
{
case AutoAssemblyState.LayerAInspecting:
return "A层";
case AutoAssemblyState.LayerBInspecting:
return "B层";
case AutoAssemblyState.LayerCInspecting:
return "C层";
case AutoAssemblyState.ProductCompleted:
return "整机";
case AutoAssemblyState.Faulted:
return "故障";
case AutoAssemblyState.Stopped:
return "已停止";
default:
return "空闲";
}
}
///
/// 若当前状态允许指定触发器,则触发状态机。
///
/// 触发器。
private void FireIfPermitted(AutoAssemblyTrigger trigger)
{
if (_stateMachine.CanFire(trigger))
{
_stateMachine.Fire(trigger);
}
}
///
/// 输出日志(允许日志委托为空)。
///
/// 日志内容。
private void WriteLog(string message)
{
_logger?.Invoke(message);
}
///
/// 已释放保护。
///
private void ThrowIfDisposed()
{
if (_isDisposed)
{
throw new ObjectDisposedException(nameof(AutoAssemblyWorkflowController));
}
}
}
}