Files

208 lines
7.7 KiB
C#
Raw Permalink Normal View History

using MaxwellFramework.Core.Attributes;
using MainShell.Alarm;
using MainShell.Hardware;
using MainShell.Log;
using MainShell.Motion.Safety;
using MwFramework.Device;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MainShell.Motion
{
[Singleton]
public sealed class MotionAlarmReporter
{
private readonly AlarmOperate _alarmOperate;
public MotionAlarmReporter(AlarmOperate alarmOperate)
{
_alarmOperate = alarmOperate ?? throw new ArgumentNullException(nameof(alarmOperate));
}
public async Task<bool> ReportAlarmAsync(int? alarmId)
{
if (!alarmId.HasValue)
{
return false;
}
await _alarmOperate.AlertAsync(alarmId.Value).ConfigureAwait(false);
return true;
}
}
[Singleton]
public sealed class StagePlatformSafetyOptionsProvider
{
private const double DefaultMaxPlaneSpread = 5.0d;
private const double DefaultMaxTravelPerStep = 10.0d;
public StagePlatformSafetyOptions GetOptions()
{
return new StagePlatformSafetyOptions(DefaultMaxPlaneSpread, DefaultMaxTravelPerStep);
}
}
[Singleton]
public sealed class MotionPrecheckService
{
private readonly MotionAlarmReporter _motionAlarmReporter;
private readonly IReadOnlyList<IMotionSafetyCheck> _motionSafetyChecks;
public MotionPrecheckService(HardwareManager hardware, MotionSafetyStateProvider motionSafetyStateProvider, MotionAlarmReporter motionAlarmReporter, StagePlatformSafetyOptionsProvider stagePlatformSafetyOptionsProvider)
{
if (hardware == null)
{
throw new ArgumentNullException(nameof(hardware));
}
if (motionSafetyStateProvider == null)
{
throw new ArgumentNullException(nameof(motionSafetyStateProvider));
}
_motionAlarmReporter = motionAlarmReporter ?? throw new ArgumentNullException(nameof(motionAlarmReporter));
var stagePlatformSafetyOptions = (stagePlatformSafetyOptionsProvider ?? throw new ArgumentNullException(nameof(stagePlatformSafetyOptionsProvider))).GetOptions();
_motionSafetyChecks = new IMotionSafetyCheck[]
{
new MotionRequestDuplicateAxisCheck(),
new MotionBatchSameSourceCheck(),
new EmergencyStopReleasedCheck(motionSafetyStateProvider),
new SafetyDoorClosedCheck(motionSafetyStateProvider),
new AutoFlowModeCheck(motionSafetyStateProvider),
new StageVacuumReadyCheck(motionSafetyStateProvider),
new BondHeadSafePositionCheck(motionSafetyStateProvider),
new StagePlatformPlaneMoveSafetyCheck(hardware, stagePlatformSafetyOptions)
};
}
public async Task ValidateAsync(MotionSafetyContext context, CancellationToken cancellationToken, int? fallbackAlarmId)
{
cancellationToken.ThrowIfCancellationRequested();
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
foreach (var check in _motionSafetyChecks)
{
var result = check.Check(context);
if (result == null || result.IsPassed)
{
continue;
}
var failureMessage = string.Format("Motion precheck failed. Rule:{0} Kind:{1} Source:{2} Message:{3}", result.RuleName, context.RequestKind, context.Source ?? "N/A", result.Message);
failureMessage.LogSysError();
var alarmId = result.AlarmId ?? fallbackAlarmId;
if (alarmId.HasValue)
{
await _motionAlarmReporter.ReportAlarmAsync(alarmId).ConfigureAwait(false);
}
throw new InvalidOperationException(failureMessage);
}
}
}
[Singleton]
public sealed class MotionExecutionLogger
{
public void HandleMotionStarted(object sender, MotionStartedEventArgs e)
{
try
{
string.Format("Axis:{0} Motion:{1} Started StartPos:{2:F3} Target:{3}", e.AxisName, e.Operation, e.StartPosition, e.TargetPosition.HasValue ? e.TargetPosition.Value.ToString("F3") : "N/A").LogInfo();
}
catch (Exception ex)
{
string.Format("Axis:{0} motion start log failed. Error:{1}", e.AxisName, ex.Message).LogSysError();
}
}
public void HandleMotionFinished(object sender, MotionFinishedEventArgs e)
{
try
{
var result = e.Result;
var message = string.Format("Axis:{0} Motion:{1} Finished Success:{2} Cancelled:{3} EndPos:{4:F3} Duration:{5}ms FailureStage:{6}", result.AxisName, result.Operation, result.Succeeded, result.Cancelled, result.EndPosition, result.DurationMilliseconds, result.FailureStage ?? "N/A");
if (result.Succeeded)
{
message.LogInfo();
return;
}
var error = string.Format("{0} Error:{1}", message, result.Exception);
error.LogSysError();
}
catch (Exception ex)
{
string.Format("Axis:{0} motion finish log failed. Error:{1}", e.AxisName, ex.Message).LogSysError();
}
}
}
[Singleton]
public sealed class MotionControllerRegistry
{
private readonly Dictionary<string, ControllerEntry> _controllers = new Dictionary<string, ControllerEntry>(StringComparer.OrdinalIgnoreCase);
private readonly object _syncRoot = new object();
private readonly MotionExecutionLogger _motionExecutionLogger;
private sealed class ControllerEntry
{
public ControllerEntry(IAxis axis, MotionController controller)
{
Axis = axis ?? throw new ArgumentNullException(nameof(axis));
Controller = controller ?? throw new ArgumentNullException(nameof(controller));
}
public IAxis Axis { get; }
public MotionController Controller { get; }
}
public MotionControllerRegistry(MotionExecutionLogger motionExecutionLogger)
{
_motionExecutionLogger = motionExecutionLogger ?? throw new ArgumentNullException(nameof(motionExecutionLogger));
}
public MotionController GetController(IAxis axis)
{
if (axis == null)
{
throw new ArgumentNullException(nameof(axis));
}
var axisName = axis.Name;
if (string.IsNullOrWhiteSpace(axisName))
{
return CreateController(axis);
}
lock (_syncRoot)
{
ControllerEntry entry;
if (_controllers.TryGetValue(axisName, out entry) && ReferenceEquals(entry.Axis, axis))
{
return entry.Controller;
}
var controller = CreateController(axis);
_controllers[axisName] = new ControllerEntry(axis, controller);
return controller;
}
}
private MotionController CreateController(IAxis axis)
{
var controller = new MotionController(axis);
controller.MotionStarted += _motionExecutionLogger.HandleMotionStarted;
controller.MotionFinished += _motionExecutionLogger.HandleMotionFinished;
return controller;
}
}
}